【问题标题】:How to select first item without long press using RecyclerView's SelectionTracker如何使用 RecyclerView 的 SelectionTracker 在不长按的情况下选择第一个项目
【发布时间】:2019-08-24 22:47:43
【问题描述】:

我正在构建一个应用程序,它允许用户从 RecyclerView 列表中进行选择,突出显示他们的选择。问题是为了第一次突出显示一个项目,需要长按。 (之后,只需单击一下即可进行选择。)

我在文档中没有找到任何内容来说明为什么会发生这种情况。

我正在使用SelectionTracker

特意关注这个guide

这是代码: https://github.com/marcosholgado/multiselection

期望: 我希望每次有人短按时都会选择 RecyclerView 上的项目。

现实: 用户第一次选择项目时,需要长按。

有什么想法吗?

【问题讨论】:

  • 所以场景应该像谷歌照片应用程序。长按后,照片将被选中,然后您只需点击照片进行选择。
  • 这听起来很相似,是的。但是,我不希望这种情况发生。
  • 好的。所以每次要长按点击选择?
  • 每次想要短按点击选择。
  • 短按就是直接点击

标签: java android android-recyclerview


【解决方案1】:

虽然我想不出不涉及重新实现 MotionInputHandler 和 SelectionTracker.Builder(如指南中所述)的解决方案,但有一个巧妙的技巧可以实现您想要的行为。

我们知道只要SelectionTracker 不为空,TouchInputHandler 就会在单击时选择项目。这意味着如果我们在SelectoinTracker 中保存了一些与真实列表项无关的特殊键,我们实际上以这种方式“激活”单击选择模式。但是,我们还必须确保我们的 KeyProvider 不提供相同的特殊密钥来保持我们的数据一致。

所以假设你选择了一个特殊的键,比如ghostKey,激活和停用选择模式现在只需调用mSelectionTracker.select(ghostkey) 或mSelectionTracker.clearSelection()。然后,您可以根据自己的喜好执行这些调用,例如拥有一个激活和停用选择模式的按钮,或者只是在托管视图创建过程中调用它,即onCreate、onCreateView 等。

如果您使用 Kotlin,您还可以定义一些扩展来为您包装这些调用,这样您就可以执行 mSelectionTracker.enable() 或 mSelectionTracker.disable() 之类的操作

【讨论】:

  • 还要注意,只要启用了“选择模式”,mSelectionTracker.hasSelection() 现在将返回 true,即使没有选择可见项目也是如此。因此,您可能需要进行额外检查以确保项目确实被选中。
  • 感谢您的回答!如果我理解正确,您是在建议我在第一次选择之前和任何取消选择之后选择一个不存在的项目,从而跳过长按?
  • 是的,基本上在后台选择了一个虚构的项目,只要单击一下就可以选择真实的项目
  • 我检查mSelectionTracker.hasSelection() 是否只在onSelectionChanged() 上,所以它似乎有效。谢谢!
【解决方案2】:

这就是我所做的:

binding.root.setOnClickListener {
   tracker?.let {
     if(!it.hasSelection()) it.select(binding.currItem?.uuid!!)
        binding.setVariable(BR.selected, it.isSelected(binding.currItem?.uuid))
     }

     binding.executePendingBindings()
}

我在视图上实现了一个点击监听器,检查选择跟踪器是否有任何选定的实体。如果它没有任何选择,那么我明确添加了选择,选择跟踪器会自动启用。

我认为这一定是您正在寻找的解决方案。

【讨论】:

    【解决方案3】:

    只需覆盖 SelectionHotspot 即可返回 true。这就是你所需要的

    fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> =
                object : ItemDetailsLookup.ItemDetails<Long>() {
                    override fun getPosition(): Int = adapterPosition
                    override fun getSelectionKey(): Long? = itemId
                    override fun inSelectionHotspot(e: MotionEvent): Boolean { return true }
                }
    

    【讨论】:

    • 我已经这样做了,但它不起作用。它在使用 android studio 模拟器的 API 21 和 API 26 上表现不同。在 inSelectionHotspot () 中返回 false 允许在 API 21 中长按进行选择,但仍然在 API 26 上单击。我想在 API 26 上强制长按。
    • @DeKekem 如果您想长按,请不要覆盖inSelectionHotspot 方法。它的默认行为是长按选择第一项。
    【解决方案4】:

    使用这条线

    selectionTracker.select(item.getSelectionKey());

    关于这个覆盖方法

     .withOnItemActivatedListener(new OnItemActivatedListener() {
                    @Override
                    public boolean onItemActivated(@NonNull ItemDetailsLookup.ItemDetails item, @NonNull MotionEvent e) {
                        selectionTracker.select(item.getSelectionKey());
                        return true;
                    }
                })
    

    我是这样解决的。继续编码..

    【讨论】:

      【解决方案5】:

      RecyclerView-selection 框架并非设计用于处理以下任何一种情况!!

      A.) 一个“启用多选”按钮,用于打开和关闭多选。

      B.) RecyclerView Adapters 使用多于一行的 ViewType 且不可选择。

      *如果您的范围需要 A.) 或 B.)(上),请勿使用 RecyclerView-selection 框架。

      改为将其删除并执行以下操作:

      1.) 将 Post-Api 数据字段添加到您的列表项模型:

      var isMultiSelected: Boolean = false // User has highlighted this inbox's row for multi-selection
      

      2.) 创建一个侦听器以从 Adapter 与 Fragment/Activity 进行通信:

      class MyFragment : MyFragmentListener {
      interface MyFragmentListener {
          fun myDataModelOnClick(myDataModel: MyDataModel)
          fun engageMultiSelect(selectedDataModelCount: Int)
          fun disengageMultiSelect()
      }
      override fun engageMultiSelect(selectedMyModelCount: Int) {
          // Update the fragment view for multi-select engaged conditions
          selectedCount_textView.text = selectedMyModelCount.toString()
      }
      
      override fun disengageMultiSelect() {
      // Update the fragment view for multi-select engaged conditions
      }
      

      3.) 更新您的 Adapter.onBindViewHolder() 以使用新字段

      holder.enableMultiSelectionButton.setOnClickListener {
          myModel.isMultiSelected = true
          myModel.engageMultiSelect(getMultiSelectionCount()) // Enable multi-selection
          notifyItemChanged(position)
      }
      holder.rowConstraintLayout.setOnClickListener {
          if (getMultiSelectionCount() > 0) { // Is multi-selection engaged?
              myModel.isMultiSelected = !myModel.isMultiSelected
              if (getMultiSelectionCount() > 0) { // New Item Count may still be larger than 0
                  myModelListener.engageMultiSelect(getMultiSelectionCount())
              } else {
                  myModelListener.disengageMultiSelect()
              }
              notifyItemChanged(position)
          } else {
              // Normal 'tap' when multi-selection is not engaged
          }
      }
      holder.rowConstraintLayout.setOnLongClickListener {
          myModel.isMultiSelected = !myModel.isMultiSelected
          if (getMultiSelectionCount() > 0) { // Is multi-selection engaged?
              myModelListener.engageMultiSelect(getMultiSelectionCount())
          } else {
              myModelListener.disengageMultiSelect()
          }
          notifyItemChanged(position)
          true
      }
      if (myModel.isMultiSelected) {
          holder.rowConstraintLayout.setBackgroundColor(R.id.coolcolor)
      } else {
          holder.rowConstraintLayout.setBackgroundColor(R.id.white)
      }
      

      【讨论】:

      • 可以在 MyModelAdapter 的构造函数类 MyModelAdapter(private val myModelFragmentListener: myModelFragmentListener) 中将 MyModelFragmentListener 添加到 MyModelAdapter 中
      【解决方案6】:

      在您的 ViewHolder 中,设置 onClickListener 并在其中使用 SelectionTracker.hasSelection() 检查您是否有任何选定的项目,如果返回 false,只需使用 SelectionTracker.select(getItemDetails().getSelectionKey()) 选择该项目 像这样:

      itemView.setOnClickListener(v -> {
          if (!tracker.hasSelection())
              tracker.select(getItemDetails().getSelectionKey());
          });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-06
        • 2015-07-21
        • 1970-01-01
        • 2011-05-02
        • 2015-12-17
        相关资源
        最近更新 更多