文章目录
Android 事件分发 系列文章目录
一、onTouchEvent 事件消费源码分析
1、onTouchEvent 方法
2、moveIfNecessary 方法
二、ItemTouchHelper 涉及到的本博客相关源码
一、onTouchEvent 事件消费源码分析
在上一篇博客 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 ) 主要分析了 给 RecyclerView 设置的 OnItemTouchListener 监听器的 onInterceptTouchEvent 触摸事件拦截方法 , 本篇博客中主要分析另外一个 触摸事件消费方法 onTouchEvent ;
在 onTouchEvent 事件消费 中 , 只处理 MotionEvent.ACTION_MOVE 事件 , 不处理其它事件 ;
1、onTouchEvent 方法
首先要获取操作的条目组件 ,
ViewHolder viewHolder = mSelected;
其中 mSelected 是在第一次按下时进行的赋值 , 有了 mSelected 值后 , 开始处理滑动事件 ;
如果没有获取到 mSelected , 则直接返回 ;
if (viewHolder == null) { return; }
如果当前处于拖动事件 MotionEvent.ACTION_MOVE , 则进行拖动事件处理 ;
拖动事件的核心是 moveIfNecessary 方法 , 该方法是处理滑动事件的核心方法
switch (action) { case MotionEvent.ACTION_MOVE: { // 检查该操作是否在拖动 // Find the index of the active pointer and fetch its position if (activePointerIndex >= 0) { // 记录修改偏移值 updateDxDy(event, mSelectedFlags, activePointerIndex); // 处理拖动事件 moveIfNecessary(viewHolder); mRecyclerView.removeCallbacks(mScrollRunnable); mScrollRunnable.run(); mRecyclerView.invalidate(); } break; }
2、moveIfNecessary 方法
moveIfNecessary 方法中主要进行拖动事件判定 , 一般是拖动条目组件进行重新排序 ;
先获取开发者自定义的 Callback 中的 public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder)方法返回值 , 如果开发者没有设置 , 就使用默认值 ;
该值的作用是 设置 拖动幅度 , 组件在宽度 / 高度 上移动超过该比例 , 就认为拖动触发, 执行拖动相关操作 ;
// 该方法就是 开发者 自定义 Callback 中的 // public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) // 方法的作用是设置 拖动幅度 // 组件在宽度 / 高度 上移动超过该比例 , 就认为拖动触发, 执行拖动相关操作 // 拖动多少系数 , 才算完成 拖动操作 final float threshold = mCallback.getMoveThreshold(viewHolder); final int x = (int) (mSelectedStartX + mDx); final int y = (int) (mSelectedStartY + mDy);
获取到拖动系数后 , 使用了 threshold 系数 乘以 水平 / 垂直 方向上的条目组件 宽度 / 高度 ;
如果拖动比例超过在 水平 / 垂直 方向上的条目组件 宽度 / 高度 乘以 threshold 的值 , 则拖动判定成功 , 执行响应的方法 ;
如果拖动比例没有超过该值 , 说明没有触发拖动操作 , 直接返回 ;
// 在该判断中 , 使用了 threshold 系数 乘以 水平 / 垂直 方向上的条目组件宽度 ; // 如果拖动比例超过在 水平 / 垂直 方向上的条目组件 宽度 / 高度 乘以 threshold 的值 // 则拖动判定成功 , 执行响应的方法 // 如果拖动比例没有超过该值 , 说明没有触发拖动操作 , 直接返回 if (Math.abs(y - viewHolder.itemView.getTop()) < viewHolder.itemView.getHeight() * threshold && Math.abs(x - viewHolder.itemView.getLeft()) < viewHolder.itemView.getWidth() * threshold) { return; }
继续向后执行 , 说明拖动动作判定成功 , 执行拖动响应方法 , 即开发者自定义的 Callback 中的 onMove 方法 ;
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target)
先获取拖动的起始位置和目标位置 , 然后传入 onMove 方法 , 触发回调 ;
// 获取被拖动的目标位置 final int toPosition = target.getAdapterPosition(); // 获取被拖动的起始位置 final int fromPosition = viewHolder.getAdapterPosition(); // 拖动判定成功 , 调用开发者实现的 Callback 的 // public boolean onMove(@NonNull RecyclerView recyclerView, // @NonNull RecyclerView.ViewHolder viewHolder, // @NonNull RecyclerView.ViewHolder target) 方法 // 一般是拖动交换数据 if (mCallback.onMove(mRecyclerView, viewHolder, target)) { // keep target visible mCallback.onMoved(mRecyclerView, viewHolder, fromPosition, target, toPosition, x, y); }