我正在尝试使用a RecyclerView
作为横向ListView
.我试图弄清楚如何突出显示所选项目.当我点击其中一个项目时,它会被选中并正确突出显示,但是当我点击另一个项目时,第二个项目会被旧项目突出显示.
这是我的onClick函数:
@Override public void onClick(View view) { if(selectedListItem!=null){ Log.d(TAG, "selectedListItem " + getPosition() + " " + item); selectedListItem.setBackgroundColor(Color.RED); } Log.d(TAG, "onClick " + getPosition() + " " + item); viewHolderListener.onIndexChanged(getPosition()); selectedPosition = getPosition(); view.setBackgroundColor(Color.CYAN); selectedListItem = view; }
这是onBindViewHolder
:
@Override public void onBindViewHolder(ViewHolder viewHolder, int position) { viewHolder.setItem(fruitsData[position]); if(selectedPosition == position) viewHolder.itemView.setBackgroundColor(Color.CYAN); else viewHolder.itemView.setBackgroundColor(Color.RED); }
zIronManBox.. 143
这是一种非常简单的方法.
private int selectedPos = RecyclerView.NO_POSITION;
在RecyclerView Adapter类中有一个,并在onBindViewHolder方法下尝试:
@Override public void onBindViewHolder(ViewHolder viewHolder, int position) { viewHolder.itemView.setSelected(selectedPos == position); }
并在您的OnClick事件中修改:
@Override public void onClick(View view) { notifyItemChanged(selectedPos); selectedPos = getLayoutPosition(); notifyItemChanged(selectedPos); }
就像Navigtional Drawer和其他RecyclerView物品适配器的魅力一样.
注意:务必使用像colabug澄清的选择器在布局中使用背景颜色:
否则setSelected(..)将不执行任何操作,使此解决方案无效.
看看我的解决方案.我想你应该在持有人中设置选定的位置并将其作为标记传递.应该在onCreateViewHolder(...)方法中设置视图.还有正确的位置来设置侦听器的视图,如OnClickListener或LongClickListener.
请查看下面的示例并阅读代码注释.
public class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder> { //Here is current selection position private int mSelectedPosition = 0; private OnMyListItemClick mOnMainMenuClickListener = OnMyListItemClick.NULL; ... // constructor, method which allow to set list yourObjectList @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { //here you prepare your view // inflate it // set listener for it final ViewHolder result = new ViewHolder(view); final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.your_view_layout, parent, false); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //here you set your current position from holder of clicked view mSelectedPosition = result.getAdapterPosition(); //here you pass object from your list - item value which you clicked mOnMainMenuClickListener.onMyListItemClick(yourObjectList.get(mSelectedPosition)); //here you inform view that something was change - view will be invalidated notifyDataSetChanged(); } }); return result; } @Override public void onBindViewHolder(ViewHolder holder, int position) { final YourObject yourObject = yourObjectList.get(position); holder.bind(yourObject); if(mSelectedPosition == position) holder.itemView.setBackgroundColor(Color.CYAN); else holder.itemView.setBackgroundColor(Color.RED); } // you can create your own listener which you set for adapter public void setOnMainMenuClickListener(OnMyListItemClick onMyListItemClick) { mOnMainMenuClickListener = onMyListItemClick == null ? OnMyListItemClick.NULL : onMyListItemClick; } static class ViewHolder extends RecyclerView.ViewHolder { ViewHolder(View view) { super(view); } private void bind(YourObject object){ //bind view with yourObject } } public interface OnMyListItemClick { OnMyListItemClick NULL = new OnMyListItemClick() { @Override public void onMyListItemClick(YourObject item) { } }; void onMyListItemClick(YourObject item); } }
正如Pawan在评论中提到的关于不使用该固定位置的IDE警告,我刚刚修改了我的代码如下.点击监听器被移动到
ViewHolder
,在那里我得到位置使用getAdapterPosition()
方法
int selected_position = 0; // You have to set this globally in the Adapter class @Override public void onBindViewHolder(ViewHolder holder, int position) { Item item = items.get(position); // Here I am just highlighting the background holder.itemView.setBackgroundColor(selected_position == position ? Color.GREEN : Color.TRANSPARENT); } public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public ViewHolder(View itemView) { super(itemView); itemView.setOnClickListener(this); } @Override public void onClick(View v) { // Below line is just like a safety check, because sometimes holder could be null, // in that case, getAdapterPosition() will return RecyclerView.NO_POSITION if (getAdapterPosition() == RecyclerView.NO_POSITION) return; // Updating old as well as new positions notifyItemChanged(selected_position); selected_position = getAdapterPosition(); notifyItemChanged(selected_position); // Do your another stuff for your onClick } }
希望这会有所帮助.
这是一种非常简单的方法.
private int selectedPos = RecyclerView.NO_POSITION;
在RecyclerView Adapter类中有一个,并在onBindViewHolder方法下尝试:
@Override public void onBindViewHolder(ViewHolder viewHolder, int position) { viewHolder.itemView.setSelected(selectedPos == position); }
并在您的OnClick事件中修改:
@Override public void onClick(View view) { notifyItemChanged(selectedPos); selectedPos = getLayoutPosition(); notifyItemChanged(selectedPos); }
就像Navigtional Drawer和其他RecyclerView物品适配器的魅力一样.
注意:务必使用像colabug澄清的选择器在布局中使用背景颜色:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/pressed_color" android:state_pressed="true"/> <item android:drawable="@color/selected_color" android:state_selected="true"/> <item android:drawable="@color/focused_color" android:state_focused="true"/> </selector>
否则setSelected(..)将不执行任何操作,使此解决方案无效.
如果您将内容滚出视图然后返回视图,则您的实现可能会有效.当我提出你的问题时,我遇到了类似的问题.
以下文件片段对我有用.我的实现是针对多种选择,但我在那里投入了一个强制单一选择.(*1)
// an array of selected items (Integer indices) private final ArrayList<Integer> selected = new ArrayList<>(); // items coming into view @Override public void onBindViewHolder(final ViewHolder holder, final int position) { // each time an item comes into view, its position is checked // against "selected" indices if (!selected.contains(position)){ // view not selected holder.parent.setBackgroundColor(Color.LTGRAY); } else // view is selected holder.parent.setBackgroundColor(Color.CYAN); } // selecting items @Override public boolean onLongClick(View v) { // set color immediately. v.setBackgroundColor(Color.CYAN); // (*1) // forcing single selection here if (selected.isEmpty()){ selected.add(position); }else { int oldSelected = selected.get(0); selected.clear(); selected.add(position); // we do not notify that an item has been selected // because that work is done here. we instead send // notifications for items to be deselected notifyItemChanged(oldSelected); } return false; }
正如指出的在这个链接的问题,为viewHolders设置听众应该onCreateViewHolder完成.我以前忘了提这个.
我写了一个基础适配器类来自动处理使用RecyclerView的项目选择.只需从中派生适配器并使用state_selected的可绘制状态列表,就像使用列表视图一样.
我有一篇关于它的博客文章,但这里是代码:
public abstract class TrackSelectionAdapter<VH extends TrackSelectionAdapter.ViewHolder> extends RecyclerView.Adapter<VH> { // Start with first item selected private int focusedItem = 0; @Override public void onAttachedToRecyclerView(final RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); // Handle key up and key down and attempt to move selection recyclerView.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { RecyclerView.LayoutManager lm = recyclerView.getLayoutManager(); // Return false if scrolled to the bounds and allow focus to move off the list if (event.getAction() == KeyEvent.ACTION_DOWN) { if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { return tryMoveSelection(lm, 1); } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { return tryMoveSelection(lm, -1); } } return false; } }); } private boolean tryMoveSelection(RecyclerView.LayoutManager lm, int direction) { int tryFocusItem = focusedItem + direction; // If still within valid bounds, move the selection, notify to redraw, and scroll if (tryFocusItem >= 0 && tryFocusItem < getItemCount()) { notifyItemChanged(focusedItem); focusedItem = tryFocusItem; notifyItemChanged(focusedItem); lm.scrollToPosition(focusedItem); return true; } return false; } @Override public void onBindViewHolder(VH viewHolder, int i) { // Set selected state; use a state list drawable to style the view viewHolder.itemView.setSelected(focusedItem == i); } public class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View itemView) { super(itemView); // Handle item click and set the selection itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Redraw the old selection and the new notifyItemChanged(focusedItem); focusedItem = getLayoutPosition(); notifyItemChanged(focusedItem); } }); } } }
我想,我已经找到了关于如何使用RecyclerView以及我们需要的所有基本功能的最佳教程(单选+多选,高亮,涟漪,点击和删除多选等等).
这是 - > http://enoent.fr/blog/2015/01/18/recyclerview-basics/
基于此,我能够创建一个库"FlexibleAdapter",它扩展了SelectableAdapter.我认为这必须是Adapter的责任,实际上你不需要每次都重写Adapter的基本功能,让库来做,所以你可以重用相同的实现.
这个适配器非常快,它开箱即用(你不需要扩展它); 您可以为所需的每种视图类型自定义项目; ViewHolder是预定义的:已经实现了常见事件:单击和长击; 它在旋转后保持状态,并且更多.
请在您的项目中实现它.
https://github.com/davideas/FlexibleAdapter
Wiki也可用.