如何在RecyclerView中按条件禁用其余列表项的onTouch触摸事件?
结论
完全可以实现该需求,共有两种常用实现方案,可根据业务场景选择:
方案1:Adapter状态控制(兼容性最好,适用大多数场景)
无需修改触摸事件分发逻辑,实现简单,还可灵活控制单个item的可用状态:
- 在Adapter内部定义两个全局变量:锁定状态标记
private boolean isItemsLocked = false、选中的item位置private int selectedPos = -1 - 重写
onBindViewHolder方法,绑定item时判断状态:如果isItemsLocked为true且当前绑定的position不等于selectedPos,调用holder.itemView.setEnabled(false),可同时设置半透明、置灰等禁用态视觉效果;如果锁定状态解除,统一将所有item的setEnabled属性恢复为true - 在item点击回调中加判断:如果
isItemsLocked为true且当前点击的不是选中item,直接return不执行后续逻辑;如果是首次点击未锁定状态的item,将isItemsLocked设为true,记录当前点击的position,调用刷新方法更新列表状态 - 预设条件达成需要恢复点击权限时,将
isItemsLocked改回false、selectedPos重置为-1,再次刷新列表即可
方案2:RecyclerView触摸拦截(适合全局拦截所有触摸的场景)
如果需要连item内部子控件的触摸、列表滚动等操作一起拦截,可通过自定义RecyclerView实现:
- 自定义RecyclerView重写
onInterceptTouchEvent方法,内部加入锁定状态判断,锁定状态下直接返回true拦截所有触摸事件,不会向下分发给子item - 代码示例:
public class LockableRecyclerView extends RecyclerView { private boolean isTouchLocked = false; // 省略构造方法 @Override public boolean onInterceptTouchEvent(MotionEvent e) { return isTouchLocked || super.onInterceptTouchEvent(e); } public void setTouchLocked(boolean locked) { isTouchLocked = locked; } }
- 点击item后调用
recyclerView.setTouchLocked(true)即可拦截所有后续触摸操作,条件满足后调用setTouchLocked(false)恢复
注意:该方案会拦截整个RecyclerView的所有触摸行为,包括滚动、选中item的点击操作,如果需要保留选中item的可操作权限,优先选择方案1
优化建议
- 两种方案都可以配合禁用态UI效果提示用户,比如给不可点击的item设置0.5f的透明度,降低用户疑惑
- 如果使用DiffUtil做局部刷新,不需要调用全量
notifyDataSetChanged(),只刷新受影响的item即可,性能更优
内容的提问来源于stack exchange,提问作者Maria Luíza
相关产品推荐
相关产品推荐

