日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )

發(fā)布時間:2025/6/17 Android 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 ) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Android 事件分發(fā) 系列文章目錄


【Android 事件分發(fā)】事件分發(fā)源碼分析 ( 驅(qū)動層通過中斷傳遞事件 | WindowManagerService 向 View 層傳遞事件 )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( Activity 中各層級的事件傳遞 | Activity -> PhoneWindow -> DecorView -> ViewGroup )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( ViewGroup 事件傳遞機(jī)制 一 )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( ViewGroup 事件傳遞機(jī)制 二 )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( ViewGroup 事件傳遞機(jī)制 三 )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( ViewGroup 事件傳遞機(jī)制 四 | View 事件傳遞機(jī)制 )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( ViewGroup 事件傳遞機(jī)制 五 )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( ViewGroup 事件傳遞機(jī)制 六 )
【Android 事件分發(fā)】事件分發(fā)源碼分析 ( ViewGroup 事件傳遞機(jī)制 七 )

【Android 事件分發(fā)】ItemTouchHelper 簡介 ( 拖動/滑動事件 | ItemTouchHelper.Callback 回調(diào) )
【Android 事件分發(fā)】ItemTouchHelper 實(shí)現(xiàn)側(cè)滑刪除 ( 設(shè)置滑動方向 | 啟用滑動操作 | 滑動距離判定 | 滑動速度判定 | 設(shè)置動畫時間 | 設(shè)置側(cè)滑觸發(fā)操作 )
【Android 事件分發(fā)】ItemTouchHelper 實(shí)現(xiàn)拖動排序 ( 設(shè)置滑動方向 | 啟啟用長按拖動功能 | 拖動距離判定 | 設(shè)置拖動觸發(fā)操作 )

【Android 事件分發(fā)】ItemTouchHelper 事件分發(fā)源碼分析 ( 綁定 RecyclerView )
【Android 事件分發(fā)】ItemTouchHelper 源碼分析 ( OnItemTouchListener 事件監(jiān)聽器源碼分析 )


文章目錄

  • Android 事件分發(fā) 系列文章目錄
  • 一、OnItemTouchListener 事件監(jiān)聽器引入
  • 二、OnItemTouchListener 觸摸事件攔截方法 onInterceptTouchEvent
    • 1、onInterceptTouchEvent 方法簡介
    • 2、處理按下事件
    • 3、findAnimation 方法
    • 4、findChildView 方法
    • 5、動作取消
    • 6、動作完成
  • 三、ItemTouchHelper 涉及到的本博客相關(guān)源碼
  • 四、博客資源





一、OnItemTouchListener 事件監(jiān)聽器引入



在上一篇博客 【Android 事件分發(fā)】ItemTouchHelper 事件分發(fā)源碼分析 ( 綁定 RecyclerView ) 分析了 ItemTouchHelper 添加時 , 調(diào)用了 mItemTouchHelper.attachToRecyclerView(recycler_view) 方法 , 將 ItemTouchHelper 與 RecyclerView 進(jìn)行關(guān)聯(lián) , 并在 attachToRecyclerView 方法的最后 , 調(diào)用了 setupCallbacks 方法 ;

// 該方法與 destroyCallbacks 方法相對應(yīng)private void setupCallbacks() {// 配置相關(guān) ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext());mSlop = vc.getScaledTouchSlop();// 設(shè)置 RecyclerView 條目中的裝飾 , 可以在條目組件 底部 上層 繪制 Canvas 圖形 // ItemTouchHelper 繼承 RecyclerView.ItemDecorationmRecyclerView.addItemDecoration(this);// 添加了每個條目上的觸摸監(jiān)聽器 mOnItemTouchListener // 該監(jiān)聽器是定義在 ItemTouchHelper 中的成員變量 mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);mRecyclerView.addOnChildAttachStateChangeListener(this);startGestureDetection();}

上一篇博客分析到 mRecyclerView.addItemDecoration(this) 位置 , 本篇博客重點(diǎn)分析 mRecyclerView.addOnItemTouchListener(mOnItemTouchListener) 中的 mOnItemTouchListener , 這是 RecyclerView 的 ItemTouchHelper 的核心 ;


OnItemTouchListener 是 RecyclerView 中定義的作用與條目組件的觸摸監(jiān)聽器 , 主要是攔截觸摸事件方法 onInterceptTouchEvent 和 消費(fèi)觸摸事件方法 onTouchEvent ;

public class RecyclerView extends ViewGroup implements ScrollingView,NestedScrollingChild2, NestedScrollingChild3 {public interface OnItemTouchListener {boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);} }

ItemTouchHelper 事件分發(fā) , 分析手指觸摸的 按下 , 移動 , 抬起 事件 ;

在 OnItemTouchListener 觸摸監(jiān)聽器中 , onInterceptTouchEvent 方法處理的是事件攔截機(jī)制 , onTouchEvent 方法是最終消費(fèi)事件的方法 ;

onInterceptTouchEvent 事件攔截 中 , 只攔截 MotionEvent.ACTION_DOWN / MotionEvent.ACTION_CANCEL / MotionEvent.ACTION_UP 333 種事件 , 不攔截 MotionEvent.ACTION_MOVE 事件 ;

onTouchEvent 事件消費(fèi) 中 , 才處理 MotionEvent.ACTION_MOVE 事件 ;

ItemTouchHelper 沒有對子控件進(jìn)行事件分發(fā) , 其只識別一層組件 , 如果內(nèi)部有多層組件 , 內(nèi)層的組件無法分發(fā)到事件 ;





二、OnItemTouchListener 觸摸事件攔截方法 onInterceptTouchEvent




1、onInterceptTouchEvent 方法簡介


在 ItemTouchHelper 中定義的成員變量

private final OnItemTouchListener mOnItemTouchListener = new OnItemTouchListener() {// 攔截觸摸事件 , 處理攔截機(jī)制 @Overridepublic boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,@NonNull MotionEvent event) {} }

中實(shí)現(xiàn)的 RecyclerView.OnItemTouchListener 接口的 onInterceptTouchEvent 方法 , 主要是用于作用與條目上的觸摸事件的攔截 ;

注意此處攔截的動作 , 只攔截 DOWN / UP / CANCEL 三種動作 , MOVE 動作不攔截 , 取消操作很少遇到 , 因此 , 攔截機(jī)制中 , 只負(fù)責(zé)攔截手指按下 和 抬起 操作 , 在 ItemTouchHelper 的業(yè)務(wù)邏輯中 , 不需要處理移動事件 ;


2、處理按下事件


當(dāng)檢測到 MotionEvent.ACTION_DOWN 按下操作時 , 獲取按下的 XY 坐標(biāo) , 并進(jìn)行滑動速度檢測 ;

// 注意此處攔截的動作 , 只攔截 DOWN / UP / CANCEL 三種動作 , MOVE 動作不攔截 // 取消操作很少遇到 // 因此 , 攔截機(jī)制中 , 只負(fù)責(zé)攔截手指按下 和 抬起 操作 // 在 ItemTouchHelper 的業(yè)務(wù)邏輯中 , 不需要處理移動事件 if (action == MotionEvent.ACTION_DOWN) {// 按下操作 , 得到初始 XY 坐標(biāo)位置 mActivePointerId = event.getPointerId(0);mInitialTouchX = event.getX();mInitialTouchY = event.getY();// 滑動速度檢測 obtainVelocityTracker();

ViewHolder mSelected = null; 成員是當(dāng)前正在點(diǎn)擊的 ViewHolder 條目 , 如果該 mSelected 成員為空 , 則執(zhí)行后續(xù)操作 ;

// mSelected 是當(dāng)前正在點(diǎn)擊的條目的 ViewHolder if (mSelected == null) {// 恢復(fù)動畫 , 查找手指按下的 View 子組件 , 該子組件時 RecyclerView 中的一個條目 // 用戶按下 RecyclerView 中的某個條目 // findAnimation 方法用于找到按下的條目 View , 并設(shè)置給 RecoverAnimation 恢復(fù)動畫 final RecoverAnimation animation = findAnimation(event);if (animation != null) {mInitialTouchX -= animation.mX;mInitialTouchY -= animation.mY;endRecoverAnimation(animation.mViewHolder, true);if (mPendingCleanup.remove(animation.mViewHolder.itemView)) {mCallback.clearView(mRecyclerView, animation.mViewHolder);}// 為動畫選擇 item 項 select(animation.mViewHolder, animation.mActionState);// 計算當(dāng)前移動的位置 , 初始位置 與 最后一次事件的位置 偏移值 . updateDxDy(event, mSelectedFlags, 0);}}

先恢復(fù)動畫 , 查找手指按下的 View 子組件 , 該子組件是 RecyclerView 中的一個條目 , 用戶按下 RecyclerView 中的某個條目 , findAnimation 方法用于找到按下的條目 View , 并設(shè)置給 RecoverAnimation 恢復(fù)動畫 ;


3、findAnimation 方法


在 findAnimation 方法中 , 先調(diào)用了 findChildView 方法 , 查找手指按下的 View 子組件 , 該子組件是 RecyclerView 中的一個條目 ;

// 找到手指按下所在位置的條目的 View 組件// 查找手指按下的 View 子組件 , 該子組件時 RecyclerView 中的一個條目 View target = findChildView(event);

找到該條目對應(yīng)的 View 組件后 , 遍歷恢復(fù)動畫 , 動畫中有 mViewHolder 成員 , mViewHolder 中有 itemView 成員 , 設(shè)置 anim.mViewHolder.itemView 為手指按下的子組件 , 即設(shè)置該動畫作用于 RecyclerView 的哪個條目上 ;

for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {final RecoverAnimation anim = mRecoverAnimations.get(i);if (anim.mViewHolder.itemView == target) {return anim;}}

findAnimation 方法完整代碼注釋 :

// 該方法作用 : // 用戶按下 RecyclerView 中的某個條目 // 該方法用于找到按下的條目 View , 并設(shè)置給 RecoverAnimation 恢復(fù)動畫 @SuppressWarnings("WeakerAccess") /* synthetic access */RecoverAnimation findAnimation(MotionEvent event) {if (mRecoverAnimations.isEmpty()) {return null;}// 找到手指按下所在位置的條目的 View 組件// 查找手指按下的 View 子組件 , 該子組件時 RecyclerView 中的一個條目 View target = findChildView(event);// 遍歷恢復(fù)動畫 // 動畫中有 mViewHolder 成員 , mViewHolder 中有 itemView 成員 // 設(shè)置 anim.mViewHolder.itemView 為手指按下的子組件 // 即設(shè)置該動畫作用于 RecyclerView 的哪個條目上 ; for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {final RecoverAnimation anim = mRecoverAnimations.get(i);if (anim.mViewHolder.itemView == target) {return anim;}}return null;}

4、findChildView 方法


根據(jù)按下的 X, Y 坐標(biāo) , 查找對應(yīng)的條目組件 , 先獲取觸摸的 XY 坐標(biāo) ;

final float x = event.getX();final float y = event.getY();

如果 mSelected 成員不為空 , 則直接使用 , 分支中直接返回了 ;

if (mSelected != null) {final View selectedView = mSelected.itemView;if (hitTest(selectedView, x, y, mSelectedStartX + mDx, mSelectedStartY + mDy)) {return selectedView;}}

如果 mSelected 為空 , 則開始遍歷進(jìn)行檢測 ;

for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {final RecoverAnimation anim = mRecoverAnimations.get(i);final View view = anim.mViewHolder.itemView;// 根據(jù)當(dāng)前按下的坐標(biāo) , 找到列表條目對應(yīng)的 View 組件 if (hitTest(view, x, y, anim.mX, anim.mY)) {return view;}}

findChildView 完整代碼注釋 :

@SuppressWarnings("WeakerAccess") /* synthetic access */View findChildView(MotionEvent event) {// first check elevated views, if none, then call RV// 根據(jù)按下的 X, Y 坐標(biāo) , 查找對應(yīng)的條目 final float x = event.getX();final float y = event.getY();// 如果 mSelected 成員不為空 , 則直接使用 , 分支中直接返回了 if (mSelected != null) {final View selectedView = mSelected.itemView;if (hitTest(selectedView, x, y, mSelectedStartX + mDx, mSelectedStartY + mDy)) {return selectedView;}}// 如果 mSelected 為空 , 則開始遍歷進(jìn)行檢測 for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {final RecoverAnimation anim = mRecoverAnimations.get(i);final View view = anim.mViewHolder.itemView;// 根據(jù)當(dāng)前按下的坐標(biāo) , 找到列表條目對應(yīng)的 View 組件 if (hitTest(view, x, y, anim.mX, anim.mY)) {return view;}}return mRecyclerView.findChildViewUnder(x, y);}

5、動作取消


當(dāng)攔截的動作是 MotionEvent.ACTION_CANCEL 或 action == MotionEvent.ACTION_UP 動作時 , 說明用戶取消了該動作 , 將選擇的組件置空 ;

} else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {mActivePointerId = ACTIVE_POINTER_ID_NONE;// 抬起 / 取消 時 , 選擇項 置空 . select(null, ACTION_STATE_IDLE);}

6、動作完成


ACTIVE_POINTER_ID_NONE 表示是否完成了滑動 , 如果滑動完成 , 觸發(fā)了側(cè)滑事件 , 才會進(jìn)入該 else if (mActivePointerId != ACTIVE_POINTER_ID_NONE) 分支 , 如果滑動沒有完成 , 滑到半路 , 松開手 , 條目組件縮回去了 , 則不會進(jìn)入該分支 ;

} else if (mActivePointerId != ACTIVE_POINTER_ID_NONE) {// 該分支表示滑動操作完成的分支 // ACTIVE_POINTER_ID_NONE 表示是否完成了滑動 // 如果滑動完成 , 觸發(fā)了側(cè)滑事件 , 才會進(jìn)入該分支 // 如果滑動沒有完成 , 滑到半路 , 松開手 , 條目組件縮回去了 , 則不會進(jìn)入該分支 // in a non scroll orientation, if distance change is above threshold, we// can select the item// 滑動完成后 , 記錄當(dāng)前的觸摸指針?biāo)饕?/span>final int index = event.findPointerIndex(mActivePointerId);if (DEBUG) {Log.d(TAG, "pointer index " + index);}if (index >= 0) {// 檢查是否完成了滑動操作 checkSelectForSwipe(action, event, index);}}



三、ItemTouchHelper 涉及到的本博客相關(guān)源碼



public class ItemTouchHelper extends RecyclerView.ItemDecorationimplements RecyclerView.OnChildAttachStateChangeListener {/*** Currently selected view holder*/@SuppressWarnings("WeakerAccess") /* synthetic access */ViewHolder mSelected = null;/*** The diff between the last event and initial touch.* 最后的觸摸事件和初始觸摸事件之間的坐標(biāo)差異 , 偏移值 .*/float mDx;float mDy;private final OnItemTouchListener mOnItemTouchListener = new OnItemTouchListener() {// 攔截觸摸事件 , 處理攔截機(jī)制 @Overridepublic boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,@NonNull MotionEvent event) {mGestureDetector.onTouchEvent(event);if (DEBUG) {Log.d(TAG, "intercept: x:" + event.getX() + ",y:" + event.getY() + ", " + event);}final int action = event.getActionMasked();// 注意此處攔截的動作 , 只攔截 DOWN / UP / CANCEL 三種動作 , MOVE 動作不攔截 // 取消操作很少遇到 // 因此 , 攔截機(jī)制中 , 只負(fù)責(zé)攔截手指按下 和 抬起 操作 // 在 ItemTouchHelper 的業(yè)務(wù)邏輯中 , 不需要處理移動事件 if (action == MotionEvent.ACTION_DOWN) {// 按下操作 , 得到初始 XY 坐標(biāo)位置 mActivePointerId = event.getPointerId(0);mInitialTouchX = event.getX();mInitialTouchY = event.getY();// 滑動速度檢測 obtainVelocityTracker();// mSelected 是當(dāng)前正在點(diǎn)擊的條目的 ViewHolder if (mSelected == null) {// 恢復(fù)動畫 , 查找手指按下的 View 子組件 , 該子組件時 RecyclerView 中的一個條目 // 用戶按下 RecyclerView 中的某個條目 // findAnimation 方法用于找到按下的條目 View , 并設(shè)置給 RecoverAnimation 恢復(fù)動畫 final RecoverAnimation animation = findAnimation(event);if (animation != null) {mInitialTouchX -= animation.mX;mInitialTouchY -= animation.mY;endRecoverAnimation(animation.mViewHolder, true);if (mPendingCleanup.remove(animation.mViewHolder.itemView)) {mCallback.clearView(mRecyclerView, animation.mViewHolder);}// 為動畫選擇 item 項 select(animation.mViewHolder, animation.mActionState);// 計算當(dāng)前移動的位置 , 初始位置 與 最后一次事件的位置 偏移值 . updateDxDy(event, mSelectedFlags, 0);}}} else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {mActivePointerId = ACTIVE_POINTER_ID_NONE;// 抬起 / 取消 時 , 選擇項 置空 . select(null, ACTION_STATE_IDLE);} else if (mActivePointerId != ACTIVE_POINTER_ID_NONE) {// 該分支表示滑動操作完成的分支 // ACTIVE_POINTER_ID_NONE 表示是否完成了滑動 // 如果滑動完成 , 觸發(fā)了側(cè)滑事件 , 才會進(jìn)入該分支 // 如果滑動沒有完成 , 滑到半路 , 松開手 , 條目組件縮回去了 , 則不會進(jìn)入該分支 // in a non scroll orientation, if distance change is above threshold, we// can select the item// 滑動完成后 , 記錄當(dāng)前的觸摸指針?biāo)饕?/span>final int index = event.findPointerIndex(mActivePointerId);if (DEBUG) {Log.d(TAG, "pointer index " + index);}if (index >= 0) {// 檢查是否完成了滑動操作 checkSelectForSwipe(action, event, index);}}if (mVelocityTracker != null) {mVelocityTracker.addMovement(event);}return mSelected != null;}};// 該方法作用 : // 用戶按下 RecyclerView 中的某個條目 // 該方法用于找到按下的條目 View , 并設(shè)置給 RecoverAnimation 恢復(fù)動畫 @SuppressWarnings("WeakerAccess") /* synthetic access */RecoverAnimation findAnimation(MotionEvent event) {if (mRecoverAnimations.isEmpty()) {return null;}// 找到手指按下所在位置的條目的 View 組件// 查找手指按下的 View 子組件 , 該子組件時 RecyclerView 中的一個條目 View target = findChildView(event);// 遍歷恢復(fù)動畫 // 動畫中有 mViewHolder 成員 , mViewHolder 中有 itemView 成員 // 設(shè)置 anim.mViewHolder.itemView 為手指按下的子組件 // 即設(shè)置該動畫作用于 RecyclerView 的哪個條目上 ; for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {final RecoverAnimation anim = mRecoverAnimations.get(i);if (anim.mViewHolder.itemView == target) {return anim;}}return null;}@SuppressWarnings("WeakerAccess") /* synthetic access */View findChildView(MotionEvent event) {// first check elevated views, if none, then call RV// 根據(jù)按下的 X, Y 坐標(biāo) , 查找對應(yīng)的條目 final float x = event.getX();final float y = event.getY();// 如果 mSelected 成員不為空 , 則直接使用 , 分支中直接返回了 if (mSelected != null) {final View selectedView = mSelected.itemView;if (hitTest(selectedView, x, y, mSelectedStartX + mDx, mSelectedStartY + mDy)) {return selectedView;}}// 如果 mSelected 為空 , 則開始遍歷進(jìn)行檢測 for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {final RecoverAnimation anim = mRecoverAnimations.get(i);final View view = anim.mViewHolder.itemView;// 根據(jù)當(dāng)前按下的坐標(biāo) , 找到列表條目對應(yīng)的 View 組件 if (hitTest(view, x, y, anim.mX, anim.mY)) {return view;}}return mRecyclerView.findChildViewUnder(x, y);}// 判斷刪上下左右邊距 是否在對應(yīng)子組件范圍內(nèi) private static boolean hitTest(View child, float x, float y, float left, float top) {return x >= left&& x <= left + child.getWidth()&& y >= top&& y <= top + child.getHeight();}/*** Starts dragging or swiping the given View. Call with null if you want to clear it.* 開始拖動/滑動給定的 View 組件. 如果想要清除傳入 null. * 為動畫選擇 item 項 * 該方法中進(jìn)行一系列的計算 ** @param selected The ViewHolder to drag or swipe. Can be null if you want to cancel the* current action, but may not be null if actionState is ACTION_STATE_DRAG.* @param actionState The type of action*/@SuppressWarnings("WeakerAccess") /* synthetic access */void select(@Nullable ViewHolder selected, int actionState) {if (selected == mSelected && actionState == mActionState) {return;}mDragScrollStartTimeInMs = Long.MIN_VALUE;final int prevActionState = mActionState;// prevent duplicate animationsendRecoverAnimation(selected, true);mActionState = actionState;if (actionState == ACTION_STATE_DRAG) {if (selected == null) {throw new IllegalArgumentException("Must pass a ViewHolder when dragging");}// we remove after animation is complete. this means we only elevate the last drag// child but that should perform good enough as it is very hard to start dragging a// new child before the previous one settles.mOverdrawChild = selected.itemView;addChildDrawingOrderCallback();}int actionStateMask = (1 << (DIRECTION_FLAG_COUNT + DIRECTION_FLAG_COUNT * actionState))- 1;boolean preventLayout = false;if (mSelected != null) {final ViewHolder prevSelected = mSelected;if (prevSelected.itemView.getParent() != null) {final int swipeDir = prevActionState == ACTION_STATE_DRAG ? 0: swipeIfNecessary(prevSelected);releaseVelocityTracker();// find where we should animate tofinal float targetTranslateX, targetTranslateY;int animationType;switch (swipeDir) {case LEFT:case RIGHT:case START:case END:targetTranslateY = 0;targetTranslateX = Math.signum(mDx) * mRecyclerView.getWidth();break;case UP:case DOWN:targetTranslateX = 0;targetTranslateY = Math.signum(mDy) * mRecyclerView.getHeight();break;default:targetTranslateX = 0;targetTranslateY = 0;}if (prevActionState == ACTION_STATE_DRAG) {animationType = ANIMATION_TYPE_DRAG;} else if (swipeDir > 0) {animationType = ANIMATION_TYPE_SWIPE_SUCCESS;} else {animationType = ANIMATION_TYPE_SWIPE_CANCEL;}getSelectedDxDy(mTmpPosition);final float currentTranslateX = mTmpPosition[0];final float currentTranslateY = mTmpPosition[1];final RecoverAnimation rv = new RecoverAnimation(prevSelected, animationType,prevActionState, currentTranslateX, currentTranslateY,targetTranslateX, targetTranslateY) {@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);if (this.mOverridden) {return;}if (swipeDir <= 0) {// this is a drag or failed swipe. recover immediatelymCallback.clearView(mRecyclerView, prevSelected);// full cleanup will happen on onDrawOver} else {// wait until remove animation is complete.mPendingCleanup.add(prevSelected.itemView);mIsPendingCleanup = true;if (swipeDir > 0) {// Animation might be ended by other animators during a layout.// We defer callback to avoid editing adapter during a layout.postDispatchSwipe(this, swipeDir);}}// removed from the list after it is drawn for the last timeif (mOverdrawChild == prevSelected.itemView) {removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView);}}};final long duration = mCallback.getAnimationDuration(mRecyclerView, animationType,targetTranslateX - currentTranslateX, targetTranslateY - currentTranslateY);rv.setDuration(duration);mRecoverAnimations.add(rv);rv.start();preventLayout = true;} else {removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView);mCallback.clearView(mRecyclerView, prevSelected);}mSelected = null;}if (selected != null) {mSelectedFlags =(mCallback.getAbsoluteMovementFlags(mRecyclerView, selected) & actionStateMask)>> (mActionState * DIRECTION_FLAG_COUNT);mSelectedStartX = selected.itemView.getLeft();mSelectedStartY = selected.itemView.getTop();mSelected = selected;if (actionState == ACTION_STATE_DRAG) {mSelected.itemView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);}}final ViewParent rvParent = mRecyclerView.getParent();if (rvParent != null) {rvParent.requestDisallowInterceptTouchEvent(mSelected != null);}if (!preventLayout) {mRecyclerView.getLayoutManager().requestSimpleAnimationsInNextLayout();}mCallback.onSelectedChanged(mSelected, mActionState);mRecyclerView.invalidate();}// 計算當(dāng)前移動的位置 @SuppressWarnings("WeakerAccess") /* synthetic access */void updateDxDy(MotionEvent ev, int directionFlags, int pointerIndex) {final float x = ev.getX(pointerIndex);final float y = ev.getY(pointerIndex);// Calculate the distance movedmDx = x - mInitialTouchX;mDy = y - mInitialTouchY;if ((directionFlags & LEFT) == 0) {mDx = Math.max(0, mDx);}if ((directionFlags & RIGHT) == 0) {mDx = Math.min(0, mDx);}if ((directionFlags & UP) == 0) {mDy = Math.max(0, mDy);}if ((directionFlags & DOWN) == 0) {mDy = Math.min(0, mDy);}}}



四、博客資源



博客資源 :

  • GitHub 地址 : https://github.com/han1202012/001_RecyclerView

總結(jié)

以上是生活随笔為你收集整理的【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。