recyclerview item子view点击事件_RecyclerView的ItemTouchHelper学习

本文详细介绍了如何使用ItemTouchHelper实现RecyclerView的侧滑删除和长按拖动功能,包括ItemTouchHelper的绑定、事件拦截、调用时机及Callback的相关方法。通过分析源码,揭示了ItemTouchHelper在RecyclerView手势事件处理中的作用,以及onSwiped和onMove方法的调用条件。
摘要由CSDN通过智能技术生成

ItemTouchHelper的使用

ItemTouchHelper可以解释为:Item点击的帮助类,它可以判断帮助我们快速的实现侧滑Swiped长按拖动Move的效果。如下图的效果,用ItemTouchHelper就可以很简单的实现。644a056b8ca78534e80412f606de4801.gif

1.实现ItemTouchHelper.CallBack接口这个接口我们可以决定是否可以侧滑和拖动,以及方向,并知道侧滑、拖动的执行时的方法回调

class DefaultItemTouchHelper(private var itemTouchStatus: ItemTouchStatus) :
  ItemTouchHelper.Callback() {

  /**
   * dragFlags:拖动支持的方向
   * swipeFlags: 滑动支持的方向
   */
  override fun getMovementFlags(
      recyclerView: RecyclerView,
      viewHolder: RecyclerView.ViewHolder
  ): Int {
      val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
      val swipeFlags = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
      // 通过makeMovementFlags确定拖动、侧滑的方向
      return makeMovementFlags(dragFlags, swipeFlags)
  }

  // 长按拖动
  override fun onMove(
      recyclerView: RecyclerView,
      viewHolder: RecyclerView.ViewHolder,
      target: RecyclerView.ViewHolder
  ): Boolean {
      return itemTouchStatus.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
  }

  // 侧滑
  override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
      itemTouchStatus.onItemRemove(viewHolder.adapterPosition)
  }
}

在拖动、侧滑对Adapter进行数据更新

public class RvAdapter extends RecyclerView.Adapter implements ItemTouchStatus {
     
  // ....省略Adapter的View创建和数据绑定
   // 侧滑删除
  @Override
  public void onItemRemove(int position) {
      data.remove(position);
      notifyItemRemoved(position);
  }
   //长按拖动数据交换
  @Override
  public boolean onItemMove(int position, int targetPosition) {
      Collections.swap(data, position, targetPosition);
      notifyItemMoved(position, targetPosition);return true;
  }
}
[Activity]将Rv绑到ItemTouchHelper中
val itemTouchHelper = ItemTouchHelper(DefaultItemTouchHelper(adapter!!))
itemTouchHelper.attachToRecyclerView(recyclerView)

实现此功能可以概括为三步

  1. 实现ItemTouchHelper.CallBack接口
  2. ItemTouchHelper实例化时将CallBack传给实例
  3. 通过ItemTouchHelper. attachToRecyclerView将RecyclerView绑定到ItemTouchHelper中。

ItemTouchHelper源码学习

带着问题看源码:

  1. 为什么RecyclerView的Item在侧滑的时候会调用ItemTouchHelper.CallBack.onSwiped方法?
  2. 为什么RecyclerView的Item在长按拖动的时候会调用ItemTouchHelper.CallBack.onMoved方法?
  3. 为什么只通过一行代码attachToRecyclerView绑定RecyclerView后就可以操作RecyclerView的监听事件?
ItemTouchHelper的绑定

先看看ItemTouchHelper的构造函数attachToRecyclerView  [ItemTouchHelper#attachToRecyclerView]

 // 接口实例
  public ItemTouchHelper(@NonNull Callback callback) {
      mCallback = callback;
  }

  public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
      if (mRecyclerView == recyclerView) {
          return; // nothing to do
      }
      // 有旧的RecyclerView,则取消原有监听
      if (mRecyclerView != null) {
          destroyCallbacks();
      }
      mRecyclerView = recyclerView;
      if (recyclerView != null) {
          final Resources resources = recyclerView.getResources();
          mSwipeEscapeVelocity = resources
                  .getDimension(R.dimen.item_touch_helper_swipe_escape_velocity);
          mMaxSwipeVelocity = resources
                  .getDimension(R.dimen.item_touch_helper_swipe_escape_max_velocity);
          // 设置监听
          setupCallbacks();
      }
  }

  private void setupCallbacks() {
      ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext());
      mSlop = vc.getScaledTouchSlop();
      mRecyclerView.addItemDecoration(this);
      // 这个监听很重要,可以截取RecylerView的手势事件
      mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);
      mRecyclerView.addOnChildAttachStateChangeListener(this);
      startGestureDetection();
  }

我们在使用ItemTouchHelper时,也就是用到这个类中的两个方法, 一构造函数必须传一个CallBack接口的实例。二是attachToRecyclerView方法会给传来的RecyclerView设置监听,其中设置了OnItemTouchListener监听可以拦截RecyclerView的手势事件,从而使ItemTouchHelper可以拦截RecylerView的事件进行处理。startGestureDetection()方法创建了GestureDetection用来识别长按手势。

RecyclerView的事件托管

onInterceptTouchEvent[RecyclerView.onInterceptTouchEvent]

   // 是否拦截事件
  @Override
  public boolean onInterceptTouchEvent(MotionEvent e) {
      if (mLayoutSuppressed) {
          // When layout is suppressed,  RV does not intercept the motion event.
          // A child view e.g. a button may still get the click.
          return false;
      }

      // 当前处理的OnItemTouchListener,重新设置为null
      mInterceptingOnItemTouchListener = null;
      // 先检查是否设置了OnItemTouchListener,那就事件先交给OnItemTouchListener处理
      if (findInterceptingOnItemTouchListener(e)) {
           // 取消滑动
          cancelScroll();
          return true;
      }
      // RecylerView自身处理拦截事件
      //....
   }

  private boolean findInterceptingOnItemTouchListener(MotionEvent e) {
      int action = e.getAction();
       // 遍历onItemTouchListener集合
      final int listenerCount = mOnItemTouchListeners.size();
      for (int i = 0; i           final OnItemTouchListener listener = mOnItemTouchListeners.get(i);
          //执行监听实例的onInterceptTouchEvent方法,如果返回ture和手势不是取消事件,则设置当前处理的OnItemTouchListener和返回Ture拦截事件。
          if (listener.onInterceptTouchEvent(this, e) && action != MotionEvent.ACTION_CANCEL) {
              mInterceptingOnItemTouchListener = listener;
              return true;
          }
      }
      return false;
  }

RecyclerView在执行拦截事件onInterceptTouchEvent会先遍历OnItemTouchListener集合,查找在OnItemTouchListener.onInterceptTouchEvent中返回true的OnItemTouchListener,并把它设置为当前处理的onItemToucheListener,返回Ture拦截事件且不执行RecyclerView本身处理的onInterceptTouchEvent代码。

onTouchEvent[RecyclerView.onToucheEvent]

  @Override
  public boolean onTouchEvent(MotionEvent e) {
      if (mLayoutSuppressed || mIgnoreMotionEventTillDown) {
          return false;
      }
      // 如果有当前处理的OnItemTouchListener
      if (dispatchToOnItemTouchListeners(e)) {
          cancelScroll();
          return true;
      }
    //....RecyclerView自身对onTouchEvent方法的处理
   }

  private boolean dispatchToOnItemTouchListeners(MotionEvent e) {
      
      if (mInterceptingOnItemTouchListener == null) {
          // 手势开始时,没有要处理的OnItemTouchListener则返回false
          if (e.getAction() == MotionEvent.ACTION_DOWN) {
              return false;
          }
          // 手势在其他事件时,在去询问一下是否拦截,防止中途变更未及时更新
          return findInterceptingOnItemTouchListener(e);
      } else {
          // 调用OnItemTouchListener的.onTouchEvent()方法
 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 Kotlin 中使用 RecyclerView 实现左滑删除 item 的代码实现: 1. 在 RecyclerViewitem 布局文件中添加一个滑动删除的按钮,例如使用 ImageButton 实现: ```xml <ImageButton android:id="@+id/btn_delete" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@color/colorAccent" android:padding="16dp" android:src="@drawable/ic_delete" /> ``` 2. 在 RecyclerViewViewHolder 中设置按钮的点事件,并定义一个接口用于回调删除事件: ```kotlin class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { fun bind(item: MyItem, listener: OnItemClickListener) = with(itemView) { // 绑定 item 数据 // ... // 设置删除按钮点事件 btn_delete.setOnClickListener { listener.onDeleteClick(adapterPosition) } } } interface OnItemClickListener { fun onDeleteClick(position: Int) } ``` 3. 在 RecyclerView 的 Adapter 中实现删除事件的回调: ```kotlin class MyAdapter(private val items: List<MyItem>, private val listener: OnItemClickListener) : RecyclerView.Adapter<MyViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_my, parent, false) return MyViewHolder(view) } override fun getItemCount() = items.size override fun onBindViewHolder(holder: MyViewHolder, position: Int) { holder.bind(items[position], listener) } fun deleteItem(position: Int) { // 删除数据 // ... // 刷新界面 notifyItemRemoved(position) } } ``` 4. 在 Activity 或 Fragment 中实现删除事件的具体操作: ```kotlin class MyActivity : AppCompatActivity(), OnItemClickListener { private lateinit var adapter: MyAdapter private lateinit var recyclerView: RecyclerView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_my) // 初始化 RecyclerView 和 Adapter recyclerView = findViewById(R.id.recycler_view) adapter = MyAdapter(getMyItems(), this) recyclerView.adapter = adapter // 设置 RecyclerView 的左滑删除功能 val swipeHandler = object : SwipeToDeleteCallback(this) { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { val position = viewHolder.adapterPosition adapter.deleteItem(position) } } val itemTouchHelper = ItemTouchHelper(swipeHandler) itemTouchHelper.attachToRecyclerView(recyclerView) } override fun onDeleteClick(position: Int) { // 在这里实现删除 item 的具体操作,例如弹出确认对话框等 // ... // 删除 item adapter.deleteItem(position) } } ``` 以上就是使用 Kotlin 实现 RecyclerView 左滑删除 item 的代码实现。注意,其中使用了 SwipeToDeleteCallback 类来实现左滑删除的功能,这个类需要自己实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值