如何正确突出显示 RecyclerView 上的选定项目?
Posted
技术标签:
【中文标题】如何正确突出显示 RecyclerView 上的选定项目?【英文标题】:How to properly highlight selected item on RecyclerView? 【发布时间】:2015-01-27 10:20:32 【问题描述】:我正在尝试使用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);
【问题讨论】:
使用可聚焦视图对于尝试跟踪所选项目不是一个好主意。检查我的答案以获得完整的解决方案 这可以帮助你amolsawant88.blogspot.in/2015/08/… 回收站查看项目选择:***.com/a/38501676/2648035 当你还没有任何东西工作时,这很难理解,这很糟糕,因为答案会跟着标记,并且没有详细说明去哪里。 【参考方案1】:这是非常简单的方法。
在 RecyclerView Adapter 类中有一个private int selectedPos = RecyclerView.NO_POSITION;
,在 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);
对于导航抽屉和其他 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(..) 将什么都不做,使这个解决方案毫无用处。
【讨论】:
我将此解决方案与在我的行视图上设置的背景可绘制/选择器一起使用:<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>
@zIronManBox:不错,简单的方法! onClick 方法中的“selectedPosition”应该是“selectedPos”吗?
getLayoutPosition() 我无法使用。
不要只使用-1,使用RecyclerView.NO_POSITION; (即-1)
@ka3ak: getLayoutPosition 是 ViewHolder 类的方法,其对象作为绑定视图方法中的第一个参数传递。所以vieHolder.getLayoutPosition
可以访问到【参考方案2】:
更新 [2017 年 7 月 26 日]:
正如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
希望这会有所帮助。
【讨论】:
太棒了!我有点困惑,你能帮我实现一个方法,扩展这个答案,当你点击一个已经选择的项目时,如何在 else 语句中做任何事情,以便你取消选择它:else holder.itemView.setBackgroundColor(Color.TRANSPARENT); 当然可以。 @iBobb。对于未选择的项目,即其位置不等于我们的 'selected_position' 变量将必须没有背景。我使用它是因为 RecyclerView,顾名思义,回收每个项目,所以它在我们滚动时为随机行设置绿色背景,这就是我放置 ELSE 部分的原因。 (您可以通过注释掉 ELSE 部分来尝试,然后滚动您的 Recycler-view) 我认为您没有理解我的问题。您知道在任何应用程序中,当您选择某些内容时,它会突出显示。如果再次按住它,它将被取消选择。我们将如何实现它?现在我们只能使用您的代码进行选择,并且触摸并按住相同的项目没有任何作用。 有可能,但是你必须重写onLongClickListener而不是onClickListener,现在我很忙所以不能提供完整的代码,但你应该基本上这样做。 干得好,满足。对于此处未选择的代码,它对我有用,int previousselectedPosition = -2; // 全局设置。然后在这些行之后进行 notifyItemChanged(selected_position);添加下面的行, if(previousselectedPosition == selected_position) selected_position = -1; notifyItemChanged(selected_position); 其他 上一个选择位置 = selected_position; 试试这个,它会工作的。【参考方案3】:我编写了一个基础适配器类来使用 RecyclerView 自动处理项目选择。只需从中派生适配器并使用带有 state_selected 的可绘制状态列表,就像使用列表视图一样。
我有一个关于它的Blog Post Here,但这里是代码:
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);
);
【讨论】:
mRecyclerView
未在任何地方声明。我们是否应该将它作为构造函数中的参数传递并存储在字段中?
很抱歉。我的适配器是我的片段的内部类,因此它可以访问回收器视图字段。否则,是的,您可以将其作为参数传递。或者更好的是,处理 onRecyclerViewAttached
并将其存储在其中的成员变量中。
不错的答案,但为什么要使用 getChildPosition()?还有一种方法developer.android.com/reference/android/support/v7/widget/…
对不起,您的意思是我只需要导入您的TrackSelectionAdapter
类并在我的列表中使用它吗?我如何“从你的班级派生我的适配器”?请问你能回答我的问题吗?我被深深地困住了:***.com/questions/29695811/…
我试过这个,发现对 NotifyItemChanged() 的两个背靠背调用杀死了在较慢硬件上平滑滚动的任何表面。在棒棒糖更新之前,Fire TV 上的表现尤其糟糕【参考方案4】:
如in this linked question 所述,应在 onCreateViewHolder 中设置 viewHolders 的侦听器。也就是说,下面的实现最初是针对多选的,但是我在 sn-p 中抛出了一个 hack 来强制单选。(*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)
// select (set color) immediately.
v.setBackgroundColor(Color.CYAN);
// (*1)
// forcing single selection here...
if (selected.isEmpty())
selected.add(position); // (done - see note)
else
int oldSelected = selected.get(0);
selected.clear(); // (*1)... and here.
selected.add(position);
// note: We do not notify that an item has been selected
// because that work is done here. We instead send
// notifications for items which have been deselected.
notifyItemChanged(oldSelected);
return false;
【讨论】:
holder中没有父字段。 @FractalBob 显然在我的实现中。无论如何,这些代码行不是答案逻辑的一部分。这就是您将自己的逻辑放在选择/取消选择时想要发生的事情的地方。【参考方案5】:我想,我已经找到了关于如何将 RecyclerView 与我们需要的所有基本功能(单选+多选、突出显示、波纹、多选中的单击和删除等)一起使用的最佳教程。
在这里 --> http://enoent.fr/blog/2015/01/18/recyclerview-basics/
基于此,我能够创建一个库“FlexibleAdapter”,它扩展了一个 SelectableAdapter。 我想这一定是Adapter的责任,其实你不需要每次都重写Adapter的基本功能,让一个库来做,你可以重用相同的实现。
这个适配器非常快,开箱即用(你不需要扩展它);您为所需的每种视图类型自定义项目; ViewHolder 已预定义:常见事件已实现:单击和长按;它保持旋转后的状态,更多。
请查看并随时在您的项目中实施它。
https://github.com/davideas/FlexibleAdapter
也可以使用 Wiki。
【讨论】:
编写该适配器的工作很棒,它似乎非常有用。唯一的问题是它确实需要一些基本的示例和文档,我什至觉得启动和运行它有点令人困惑。不过可能很棒! 是的,我没有找到足够的信息来开始。即使代码似乎已考虑到这一点,也找不到 API 参考。示例应用程序似乎 - 虽然内容广泛且内容丰富 - 如果没有图书馆的先验知识,很难理解。所有用例都绑定在一起,几乎没有迹象表明什么演示了什么,类在不同的场景中被重用,这导致它们被信息超载。我在这里用这些建议创建了一个新问题:github.com/davideas/FlexibleAdapter/issues/120 Wiki 已经完全重写,即将完成。【参考方案6】:看看我的解决方案。我想您应该在持有人中设置选定的位置并将其作为视图标签传递。 视图应该在 onCreateViewHolder(...) 方法中设置。也有正确的地方为视图设置监听器,例如 OnClickListener 或 LongClickListener。
请查看下面的示例并阅读 cmets 到代码。
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);
【讨论】:
你认为 mSelectedPosition 可以声明为静态来维护配置更改吗? 不!将其设为静态是错误的,这是非常错误的 是的。这很危险。但是为了保持配置更改(尤其是屏幕旋转),我们可以在活动中声明这个变量并从那里获取它,对吧? 有很多解决方案...您可以使用getter和setter,您可以为适配器创建自己的方法saveInstanceState并从Activity/Fragment在saveInstanceState中调用它【参考方案7】:RecyclerView 中没有像 ListView 和 GridView 这样的选择器,但你试试下面对我有用的东西
如下创建一个可绘制的选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="@color/blue" />
</shape>
</item>
<item android:state_pressed="false">
<shape>
<solid android:color="@android:color/transparent" />
</shape>
</item>
</selector>
然后将此可绘制对象设置为 RecyclerView 行布局的背景
android:background="@drawable/selector"
【讨论】:
这没什么用。它只会在按下时改变颜色。【参考方案8】:接口和回调的决策。 创建具有选择和取消选择状态的界面:
public interface ItemTouchHelperViewHolder
/**
* Called when the @link ItemTouchHelper first registers an item as being moved or swiped.
* Implementations should update the item view to indicate it's active state.
*/
void onItemSelected();
/**
* Called when the @link ItemTouchHelper has completed the move or swipe, and the active item
* state should be cleared.
*/
void onItemClear();
在 ViewHolder 中实现接口:
public static class ItemViewHolder extends RecyclerView.ViewHolder implements
ItemTouchHelperViewHolder
public LinearLayout container;
public PositionCardView content;
public ItemViewHolder(View itemView)
super(itemView);
container = (LinearLayout) itemView;
content = (PositionCardView) itemView.findViewById(R.id.content);
@Override
public void onItemSelected()
/**
* Here change of item
*/
container.setBackgroundColor(Color.LTGRAY);
@Override
public void onItemClear()
/**
* Here change of item
*/
container.setBackgroundColor(Color.WHITE);
在回调时运行状态更改:
public class ItemTouchHelperCallback extends ItemTouchHelper.Callback
private final ItemTouchHelperAdapter mAdapter;
public ItemTouchHelperCallback(ItemTouchHelperAdapter adapter)
this.mAdapter = adapter;
@Override
public boolean isLongPressDragEnabled()
return true;
@Override
public boolean isItemViewSwipeEnabled()
return true;
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
int swipeFlags = ItemTouchHelper.END;
return makeMovementFlags(dragFlags, swipeFlags);
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
...
@Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction)
...
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE)
if (viewHolder instanceof ItemTouchHelperViewHolder)
ItemTouchHelperViewHolder itemViewHolder =
(ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemSelected();
super.onSelectedChanged(viewHolder, actionState);
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
super.clearView(recyclerView, viewHolder);
if (viewHolder instanceof ItemTouchHelperViewHolder)
ItemTouchHelperViewHolder itemViewHolder =
(ItemTouchHelperViewHolder) viewHolder;
itemViewHolder.onItemClear();
使用回调创建 RecyclerView(示例):
mAdapter = new BuyItemsRecyclerListAdapter(MainActivity.this, positionsList, new ArrayList<BuyItem>());
positionsList.setAdapter(mAdapter);
positionsList.setLayoutManager(new LinearLayoutManager(this));
ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(mAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(positionsList);
在 iPaulPro 的文章中查看更多信息:https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.6gh29uaaz
【讨论】:
【参考方案9】:这是我的解决方案,您可以在一个项目(或一个组)上设置并再次单击取消选择它:
private final ArrayList<Integer> seleccionados = new ArrayList<>();
@Override
public void onBindViewHolder(final ViewHolder viewHolder, final int i)
viewHolder.san.setText(android_versions.get(i).getAndroid_version_name());
if (!seleccionados.contains(i))
viewHolder.inside.setCardBackgroundColor(Color.LTGRAY);
else
viewHolder.inside.setCardBackgroundColor(Color.BLUE);
viewHolder.itemView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
if (seleccionados.contains(i))
seleccionados.remove(seleccionados.indexOf(i));
viewHolder.inside.setCardBackgroundColor(Color.LTGRAY);
else
seleccionados.add(i);
viewHolder.inside.setCardBackgroundColor(Color.BLUE);
);
【讨论】:
【参考方案10】:@zIronManBox 答案完美无缺。虽然它不具备 recyclerView 中取消选择和取消选择项的能力。
所以
像以前一样添加一个私有 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);
还在你的布局中添加以下选择器(可绘制),其中包括一个带有透明颜色的 state_selected="false":
<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"/>
<item android:drawable="@android:color/transparent" android:state_selected="false"/>
</selector>
否则 setSelected(..) 将什么都不做,使这个解决方案毫无用处。
【讨论】:
【参考方案11】:我有同样的问题,我通过以下方式解决它:
用于在 createViewholder 中创建 Row 的 xml 文件,只需添加以下行:
android:clickable="true"
android:focusableInTouchMode="true"
android:background="?attr/selectableItemBackgroundBorderless"
或者,如果您使用 frameLayout 作为行项的父级,则:
android:clickable="true"
android:focusableInTouchMode="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
在您在点击监听器上添加的视图持有者内的 java 代码中:
@Override
public void onClick(View v)
//ur other code here
v.setPressed(true);
【讨论】:
【参考方案12】:我在网上找不到解决这个问题的好方法,我自己解决了。有很多人正在遭受这个问题的困扰。因此,我想在这里分享我的解决方案。
滚动时,行被回收。因此,选中的复选框和突出显示的行无法正常工作。我通过编写下面的适配器类解决了这个问题。
我还实施了一个完整的项目。在这个项目中,您可以选择多个复选框。包括选定复选框的行被突出显示。更重要的是,这些在滚动时不会丢失。您可以从链接下载它:
https://www.dropbox.com/s/ssm58w62gw32i29/recyclerView_checkbox_highlight.zip?dl=0
public class RV_Adapter extends RecyclerView.Adapter<RV_Adapter.ViewHolder>
public ArrayList<String> list;
boolean[] checkBoxState;
MainActivity mainActivity;
MyFragment myFragment;
View firstview;
private Context context;
FrameLayout framelayout;
public RV_Adapter()
public RV_Adapter(Context context, MyFragment m, ArrayList<String> list )
this.list = list;
myFragment = m;
this.context = context;
mainActivity = (MainActivity) context;
checkBoxState = new boolean[list.size()];
// relativeLayoutState = new boolean[list.size()];
public class ViewHolder extends RecyclerView.ViewHolder
public TextView textView;
public CheckBox checkBox;
RelativeLayout relativeLayout;
MainActivity mainActivity;
MyFragment myFragment;
public ViewHolder(View v,MainActivity mainActivity,MyFragment m)
super(v);
textView = (TextView) v.findViewById(R.id.tv_foodname);
/**/
checkBox= (CheckBox) v.findViewById(R.id.checkBox);
relativeLayout = (RelativeLayout)v.findViewById(R.id.relativelayout);
this.mainActivity = mainActivity;
this.myFragment = m;
framelayout = (FrameLayout) v.findViewById(R.id.framelayout);
framelayout.setOnLongClickListener(m);
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
firstview = inflater.inflate(R.layout.row, parent, false);
return new ViewHolder(firstview,mainActivity, myFragment);
@Override
public void onBindViewHolder( final ViewHolder holder, final int position)
holder.textView.setText(list.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
);
// When action mode is active, checkboxes are displayed on each row, handle views(move icons) on each row are disappered.
if(!myFragment.is_in_action_mode)
holder.checkBox.setVisibility(View.GONE);
else
holder.checkBox.setVisibility(View.VISIBLE);
holder.checkBox.setChecked(false);
holder.checkBox.setTag(position);
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b)
if(compoundButton.isPressed()) // ekrandan kaybolan checkbox'lar otomatik olarak state degistiriyordu ve bu listener method cagiriliyordu, bunu onlemek icin isPressed() method'u ile kullanici mi basmis diye kontrol ediyorum.
int getPosition = (Integer) compoundButton.getTag(); // Here we get the position that we have set for the checkbox using setTag.
checkBoxState[getPosition] = compoundButton.isChecked(); // Set the value of checkbox to maintain its state.
//relativeLayoutState[getPosition] = compoundButton.isChecked();
if(checkBoxState[getPosition] && getPosition == position )
holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view **/
else
holder.relativeLayout.setBackgroundResource(R.color.food_unselected); /** Change background color of the selected items in list view **/
myFragment.prepareselection(compoundButton, getPosition, holder.relativeLayout);
);
holder.checkBox.setChecked(checkBoxState[position]);
if(checkBoxState[position] )
holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view **/
else
holder.relativeLayout.setBackgroundResource(R.color.food_unselected);
@Override
public int getItemCount()
return list.size();
public void updateList(ArrayList<String> newList)
this.list = newList;
checkBoxState = new boolean[list.size()+1];
public void resetCheckBoxState()
checkBoxState = null;
checkBoxState = new boolean[list.size()];
应用截图:
【讨论】:
【参考方案13】:以编程方式
注意:不使用任何文件选择器。
涉及的步骤:
-
创建一个全局位置变量,即
int selectedPosition = -1;
整数:
-1
默认不选择
0
用于默认的第一项选择
检查变量是否等于当前位置position
public void onBindViewHolder(@NonNull ViewHolder holder, int position)
if(selectedPosition == position)
holder.itemView.setBackgroundColor(Color.GREEN); //selected
else
holder.itemView.setBackgroundColor(Color.BLACK); //not selected
....
使用setOnClickListener
方法在项目之间导航
holder.itemView.setOnClickListener(v ->
if(selectedPosition == position)
selectedPosition = -1;
notifyDataSetChanged();
return;
selectedPosition = position;
notifyDataSetChanged();
// TODO: Put your itemview clicked functionality below
);
注意
使用此代码在项目上创建切换效果:
if(selectedPosition == position)
selectedPosition = -1;
notifyDataSetChanged();
return;
selectedPosition = position;
notifyDataSetChanged();
仅使用此代码创建列表的经典选择方式(一次一个项目)
selectedPosition = position;
notifyDataSetChanged();
【讨论】:
我认为这不是一个好主意,因为当您取消选择一个项目时,onClickListener 不会被调用,这意味着您的片段将不知道您的 RecyclerView 中发生了什么。 【参考方案14】:设置private int selected_position = -1;
以防止在开始时选择任何项目。
@Override
public void onBindViewHolder(final OrdersHolder holder, final int position)
final Order order = orders.get(position);
holder.bind(order);
if(selected_position == position)
//changes background color of selected item in RecyclerView
holder.itemView.setBackgroundColor(Color.GREEN);
else
holder.itemView.setBackgroundColor(Color.TRANSPARENT);
//this updated an order property by status in DB
order.setProductStatus("0");
holder.itemView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//status switch and DB update
if (order.getProductStatus().equals("0"))
order.setProductStatus("1");
notifyItemChanged(selected_position);
selected_position = position;
notifyItemChanged(selected_position);
else
if (order.getProductStatus().equals("1"))
//calls for interface implementation in
//MainActivity which opens a new fragment with
//selected item details
listener.onOrderSelected(order);
);
【讨论】:
【参考方案15】:如果您没有背景颜色,只需添加 android:background="?attr/selectableItemBackgroundBorderless"
即可,但不要忘记使用 setSelected 方法。如果你有不同的背景颜色,我就用这个(我正在使用数据绑定);
在onClick函数中设置isSelected
b.setIsSelected(true);
并将其添加到 xml;
android:background="@ isSelected ? @color/color selected : @color/color not selected "
【讨论】:
【参考方案16】:制作选择器:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/Green_10" android:state_activated="true" />
<item android:drawable="@color/Transparent" />
</selector>
在列表项布局中将其设置为背景
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/selector_attentions_list_item"
android:layout_
android:layout_>
在您的适配器中将 OnClickListener 添加到视图(onBind 方法)
@Suppress("UNCHECKED_CAST")
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
fun bindItems(item: T)
initItemView(itemView, item)
itemView.tag = item
if (isClickable)
itemView.setOnClickListener(onClickListener)
在 onClick 事件中激活视图:
fun onItemClicked(view: View)
view.isActivated = true
【讨论】:
这有两个问题:1)您没有提供任何方法来撤消回收器中其他项目的激活。 2) 视图被重用。因此,当滚动时,相同的激活视图可能会按顺序显示。以上是关于如何正确突出显示 RecyclerView 上的选定项目?的主要内容,如果未能解决你的问题,请参考以下文章
将数据从 Firebase 检索到嵌入在 Fragment 上的 RecyclerView
为啥在recyclerview android中滚动后突出显示的项目丢失