2016-10-03 99 views
0

我有一个RecyclerView,它显示从数据库派生的一系列视图。我想确认用户已经通过突出显示其边缘来选择其中一个视图,并且我已经成功地这样做了。如果用户继续选择不同选项,我希望删除原始选择中的突出显示。这是我遇到了一些麻烦的地方。直接从RecyclerView访问ViewHolder,按位置

最初的亮点并不是什么问题,因为我是在内部做的。但是,我不知道如何使用适配器位置访问以前的视图。我一直在搜索StackOverflow大约一个小时,因为我无法在Android API或谷歌上找到很多东西。许多用户似乎提出了类似的问题,但最终,细微的差异使任何有用的答案都无效。

里面我ViewHolder,这是我RecyclerView的内部public class,我有一个OnClickListener如下:

@Override 
    public void onClick(View view) { 
     if(!selected) { 
      selected = true; 
      view.setBackgroundResource(R.drawable.default_selection_background); 
     } else { 
      selected = false; 
      view.setBackgroundResource(0); 
     } 

     UpdateSelected(getAdapterPosition()); 
    } 

这点回到我的RecyclerView,并坦率地说,我还没有添加任何的工作代码我的UpdateSelected(int position)方法。

如果有帮助,我打算把它的功能是这样的:

void UpdateSelected(int position) { 
    if(position != currentlySelected) { 
     ViewHolder[currentlySelected].Deselect(); 
    } 
} 

public class ViewHolder extends RecyclerView.ViewHolder { 
    ... 

    public void Deselect() { 
     // and from here, I can go on as normal. 
    } 
} 

我已经注意到了用户的建议他人使用getLayoutPosition()来推导UI目的位置,除非他们特别希望继续工作内部数据,这是我打算做的。

如何从我的RecyclerView使用其位置访问特定的ViewHolder?

回答

3

你可以做这样的事情。

在您的适配器中,创建一个会跟踪所选物品位置的成员变量。

int selectedPosition = -1; // -1 some default value for nothing selected 

然后在你的回收站视图适配器onBindViewHolder

int backgroundRes = (position == selectedPosition)? R.drawable.default_selection_background : 0; 
    view.setBackgroundResource(backgroundRes); 

最后,在你的viewholder的的onClick

@Override 
public void onClick(View view) { 
    selectedPosition = getAdapterPosition(); 
    notifyDataSetChanged(); 
} 
+0

太棒了!奇迹般有效。我必须做的只是在'onBindViewHolder'中,它立即可以访问'view'。我只是使用'viewHolder.itemView.setBackgroundResource(backgroundRes)'。为了提高效率,我也只在'previousSelection'和'currentSelection'上使用'notifyItemChanged',但非常感谢。 – Gnemlock

+0

我也面临同样的问题。所以我尝试这个解决方案,但在我的情况下没有工作。 @Gnemlock –

+0

我只是偶然发现了这个答案,虽然不错,但我建议将'notifyDataSetChanged()'更改为'notifyItemChanged(selectedPosition)'。 当您可以精确地告诉适配器需要更新哪些视图时,避免调用notifyDataSetChanged()是个好习惯。 –

1

您可以通过它访问viewholder是从recyclerview位置

这是我实现

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, 
       recyclerView, new RecyclerItemClickListener.OnItemClickListener() { 
      @Override 
      public void onItemClick(View view, int position) { 
       /*your coding */ 
      } 

      @Override 
      public void onItemLongClick(View view, int position) { 

      } 

     })); 

,并创建类

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { 

    private OnItemClickListener mListener; 
    private GestureDetector mGestureDetector; 
    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) { 
     mListener = listener; 

     mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 
      @Override 
      public boolean onSingleTapUp(MotionEvent e) { 
       return true; 
      } 
      @Override 
      public void onLongPress(MotionEvent e) { 
       View childView = recyclerView.findChildViewUnder(e.getX(), e.getY()); 

       if (childView != null && mListener != null) { 
        mListener.onItemLongClick(childView, recyclerView.getChildPosition(childView)); 
       } 
      } 
     }); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { 
     View childView = view.findChildViewUnder(e.getX(), e.getY()); 
     if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { 
      mListener.onItemClick(childView, view.getChildPosition(childView)); 
     } 
     return false; 
    } 

    @Override 
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { 
    } 

    @Override 
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { 

    } 
    public interface OnItemClickListener { 
     void onItemClick(View view, int position); 
     void onItemLongClick(View view, int position); 
    } 
} 
0

代替手动交换的背景资源,可以改为标记视图中选择与否,并有Android的变化的背景使用可绘制的选择器。

res/drawable/background。XML

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:state_selected="true" android:drawable="@drawable/default_selection_background" /> 
    <item android:drawable="@null" /> 
</selector> 

background.xml将被设置为你的项目的布局XML的android:background

然后在你的onBindViewHolder(ViewHolder holder, int position)您必须更新Android查看的状态:

@Override 
public void onBindViewHolder(ViewHolder holder, int position) { 
    boolean isSelected = position == selectedPosition; 
    holder.itemView.setSelected(isSelected); 
} 

对于我来说,我宁愿具有适配器这是笨并有较少的逻辑。你可以通过保留ViewModel列表(数据类代表你将在视图中显示的内容 - 不多,不少于),在其中一个属性可以是所选标记(在每个ViewModel中)的情况下做到这一点。

当用户选择或取消选择视图时,回调会向演示者发出更新,演示者然后更新适配器,并通知适配器哪些位置已更新。这意味着在演示者中保留当前选定的项目(最好是ID,但可以存储ViewModel或位置),以便更新它。