Android 滑動,攔截事件處理
不多說了上程式碼:
上面的是最主要的ViewGroup 下面在來看看 activity 中得程式碼/** * 只處理 縱向滑動事件, 其他事件不做 處理 */ public class CustomScrollViewGroup extends RelativeLayout { public static final String TAG = "CustomScrollViewGroup"; public CustomScrollViewGroup(Context context) { super(context); init(); } public CustomScrollViewGroup(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CustomScrollViewGroup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private static final int MIN_DISTANCE_FOR_FLING = 25; // dips private OnScrollListener mOnScrollListener; private int mTouchSlop; protected VelocityTracker mVelocityTracker; private int mMinimumVelocity; private int mMaximumVelocity; /** * Position of the last motion event. */ private float mLastMotionX; private float mLastMotionY; private float mInitialMotionY, mInitialMotionX; protected int mActivePointerId = INVALID_POINTER; private static final int INVALID_POINTER = -1; private boolean mIsUnableToDrag = false; private int mFlingDistance; private boolean mIsBeingDragged = false; boolean mScrollToEnd = false;//標記View是否已經完全消失,OvershootInterpolator回彈時間忽略 private boolean mQuickReturn = false; boolean isTouchOnRecycleView = false; private void init() { final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); final float density = getContext().getResources().getDisplayMetrics().density; mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { LogUtil.d(TAG, "onInterceptTouchEvent ev = " + ev.getAction()); final int action = ev.getAction(); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP || (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) { endDrag(); return false; } switch (action & MotionEventCompat.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // Remember where the motion event started int index = MotionEventCompat.getActionIndex(ev); mActivePointerId = MotionEventCompat.getPointerId(ev, index); if (mActivePointerId == INVALID_POINTER) break; mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, index); mInitialMotionY = mLastMotionY = MotionEventCompat.getY(ev, index); mIsBeingDragged = false; mIsUnableToDrag = false; break; case MotionEvent.ACTION_MOVE: final int activePointerIndex = getPointerIndex(ev, mActivePointerId); if (mActivePointerId == INVALID_POINTER) { break; } final float currentY = MotionEventCompat.getY(ev, activePointerIndex); final float deltaY = mLastMotionY - currentY; determineDrag(ev); break; } if (!mIsBeingDragged) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); } return mIsBeingDragged || mQuickReturn; } private int getPointerIndex(MotionEvent ev, int id) { int activePointerIndex = MotionEventCompat.findPointerIndex(ev, id); if (activePointerIndex == -1) mActivePointerId = INVALID_POINTER; return activePointerIndex; } private int mScrollY = 0; @Override public boolean onTouchEvent(MotionEvent ev) { LogUtil.d(TAG, "onTouchEvent ev = " + ev.getAction()); if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); final int action = ev.getAction(); switch (action & MotionEventCompat.ACTION_MASK) { case MotionEvent.ACTION_DOWN: // Remember where the motion event started int index = MotionEventCompat.getActionIndex(ev); mActivePointerId = MotionEventCompat.getPointerId(ev, index); mLastMotionY = mInitialMotionY = ev.getY(); mLastMotionX = mInitialMotionX = ev.getX(); break; case MotionEvent.ACTION_MOVE: if (!mIsBeingDragged) { determineDrag(ev); if (mIsUnableToDrag) return false; } if (mIsBeingDragged) { final int activePointerIndex = getPointerIndex(ev, mActivePointerId); if (mActivePointerId == INVALID_POINTER) break; final float y = MotionEventCompat.getY(ev, activePointerIndex); final float deltaY = mLastMotionY - y; mLastMotionY = y; float oldScrollY = mScrollY; float scrollY = oldScrollY + deltaY; mLastMotionX += scrollY - (int) scrollY; mScrollY = (int) scrollY; if (mOnScrollListener != null) { mOnScrollListener.onScroll(0, deltaY); } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mIsBeingDragged) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(velocityTracker, mActivePointerId); final int activePointerIndex = getPointerIndex(ev, mActivePointerId); if (mActivePointerId != INVALID_POINTER) { final float y = MotionEventCompat.getY(ev, activePointerIndex); final int totalDelta = (int) (y - mInitialMotionY);// doww -> up detal if (Math.abs(totalDelta) > mFlingDistance && Math.abs(initialVelocity) > mMinimumVelocity) { if (initialVelocity > 0 && totalDelta > 0) { // 向下滑 if (mOnScrollListener != null) { mOnScrollListener.onFling(false); } } else if (initialVelocity < 0 && totalDelta < 0) { // 向上滑 if (mOnScrollListener != null) { mOnScrollListener.onFling(true); } } else { if (mOnScrollListener != null) { mOnScrollListener.onScrollOver(); } } } else { if (mOnScrollListener != null) { mOnScrollListener.onScrollOver(); } // 不是 fling 最後是 劃上 還是劃下 外面判斷 } } mActivePointerId = INVALID_POINTER; endDrag(); } break; case MotionEventCompat.ACTION_POINTER_DOWN: { final int indexx = MotionEventCompat.getActionIndex(ev); mLastMotionY = MotionEventCompat.getY(ev, indexx); mLastMotionX = MotionEventCompat.getX(ev, indexx); mActivePointerId = MotionEventCompat.getPointerId(ev, indexx); break; } case MotionEventCompat.ACTION_POINTER_UP: int pointerIndex = getPointerIndex(ev, mActivePointerId); if (mActivePointerId == INVALID_POINTER) break; mLastMotionY = MotionEventCompat.getY(ev, pointerIndex); mLastMotionX = MotionEventCompat.getX(ev, pointerIndex); break; } return true; } private void determineDrag(MotionEvent ev) { final int activePointerId = mActivePointerId; final int pointerIndex = getPointerIndex(ev, activePointerId); if (activePointerId == INVALID_POINTER || pointerIndex == INVALID_POINTER) return; final float x = MotionEventCompat.getX(ev, pointerIndex); final float dx = x - mLastMotionX; final float xDiff = Math.abs(dx); final float y = MotionEventCompat.getY(ev, pointerIndex); final float dy = y - mLastMotionY; final float yDiff = Math.abs(dy); if (yDiff > mTouchSlop && yDiff > xDiff) { startDrag(); mLastMotionX = x; mLastMotionY = y; } else if (xDiff > mTouchSlop) { mIsUnableToDrag = true; } } // 開始滑動 private void startDrag() { mIsBeingDragged = true; mQuickReturn = false; mScrollToEnd = false; } private void endDrag() { mQuickReturn = false; mIsBeingDragged = false; mIsUnableToDrag = false; mActivePointerId = INVALID_POINTER; if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } public void setOnScrollListener(OnScrollListener onScrollListener) { mOnScrollListener = onScrollListener; } public interface OnScrollListener { void onScroll(float distanceX, float distanceY); void onFling(boolean isFlingUp); void onScrollOver(); } }
public class MainActivity extends AppCompatActivity { public static final String TAG = "MainActivity"; Button mButton; View mView; CustomScrollViewGroup mCustomScrollViewGroup; int maxTranY; float currentTransY = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.btn); mView = findViewById(R.id.scrolledView); mCustomScrollViewGroup = (CustomScrollViewGroup) findViewById(R.id.customscrollviewgroup); maxTranY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300, getResources().getDisplayMetrics()); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "click btn", Toast.LENGTH_SHORT).show(); } }); mCustomScrollViewGroup.setOnScrollListener(new CustomScrollViewGroup.OnScrollListener() { /** * 滑動 的箭頭 * @param distanceX 向左滑動 為正 * @param distanceY 向上滑動 為正 */ @Override public void onScroll(float distanceX, float distanceY) { if (isAnimating) { return; } currentTransY = currentTransY - distanceY; if (currentTransY < -maxTranY) { currentTransY = -maxTranY; } if (currentTransY > 0) { currentTransY = 0; } mView.setTranslationY(currentTransY); LogUtil.d(TAG, "onScroll distanceX = " + distanceX + " , distanceY = " + distanceY + ", currentTransY = " + currentTransY); } /** * 快速滑動的回撥 * @param isFlingUp 是否是向上快速滑動 */ @Override public void onFling(boolean isFlingUp) { if (isAnimating) { return; } LogUtil.d(TAG, "onFling isFlingUp = " + isFlingUp); if (isFlingUp) { animatorScrollUp(); } else { animatorScrollDowm(); } } /** * 滑動結束的監聽 */ @Override public void onScrollOver() { if (isAnimating) { return; } LogUtil.d(TAG, "onScrollOver"); if (currentTransY < -maxTranY / 2) {// 向上滑超過了 1/2 animatorScrollUp(); } else { animatorScrollDowm(); } } }); } boolean isAnimating = false; private void animatorScrollUp() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "TranslationY", mView.getTranslationY(), -maxTranY); objectAnimator.setDuration(300); isAnimating = true; objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); currentTransY = -maxTranY; isAnimating = false; } }); objectAnimator.start(); } private void animatorScrollDowm() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "TranslationY", mView.getTranslationY(), 0); objectAnimator.setDuration(300); isAnimating = true; objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); currentTransY = 0; isAnimating = false; } }); objectAnimator.start(); } }
相關推薦
Android 滑動,攔截事件處理
之前一片文章 初略的講了一些關於事件傳遞的基本內容,現在這片部落格, 主要是具體去運用事件傳遞攔截的相關內容, ok 具體要實現的目標就是, view 能夠正常的吃掉點選事件, 但是如果是滑動事件時, 則是父View 來處理來滑動另一個View 基本原理就是 在Vi
可能是最詳細的Android點選事件處理詳解(三)
前兩篇文章: 可能是最詳細的Android點選事件處理詳解 可能是最詳細的Android點選事件處理詳解(二) 這裡再次延伸一下,在ScrollView和RecyclerView巢狀中touch事件的傳遞過程,以及巢狀滑動衝突的問題。 如上圖,外層是一個Neste
可能是最詳細的Android點選事件處理詳解(二)
上一篇我們主要詳細描述了touch事件在各層的傳遞 本篇文章主要是對比touch在不可滾動和可滾動的ViewGroup事件的傳遞過程 如上圖: - 左圖:是ViewGroup巢狀View,不可滑動 - 右圖:也是ViewGroup(RecyclerView)巢
可能是最詳細的Android點選事件處理詳解
面試的時候,很多時候都會問到Touch事件的傳遞,而且問法角度都有所不同,但是還是會遵循基本的事件傳遞規則的,可能他問的你沒處理過,但是根據基本規則慢慢思考來回答,都不會錯。 一,簡介 首先我們知道touch事件 主要是是在三個方法中傳遞和處理的。分別是:
結合原始碼,重溫 Android View 的事件處理知多少 ?
前言 Android View 的 事件處理在我們的程式設計中,可謂是無處不在了。但對於大多數人而言,一直都是簡單的使用,對其原理缺乏深入地認識。 學 Android 有一段時間了,最近發現,很多基礎知識開始有些遺忘了,所以從新複習了 View 的事件分發。特地整理成了這篇文章分享給大家。 本文不難,可以作
Android事件傳遞、多點觸控及滑動衝突的處理
基本概念 所有Touch事件都會被封裝MotionEvent, 包括Touch的型別、位置(相對螢幕的絕對位置,相對View的相對位置)、時間、歷史記錄以及第幾個手指(多點觸控)等; 事件有多種型別,常用的事件型別有:ACTION_DOWN,ACTION_UP,ACTION_MOVE,ACTION
Android觸控事件的分發、攔截、處理
在Android觸控式螢幕的過程中,有三個重要的方法,dispatchTouchEvent(事件分發)、onInterceptTouchEvent(事件攔截)、onTouchEvent(事件處理、消
Android開發知識(七):Android事件處理機制:事件分發、傳遞、攔截、處理機制的原理分析(上)
在我們剛開始學習安卓的時候,總會一開始就接觸到Button,也就是對按鈕進行一個事件監聽的事件,當我們點選螢幕上的按鈕時就可以觸發一個點選事件。那麼,從我們點選螢幕到按鈕觸發事件這個過程,是什麼樣子的呢?本文我們就來談一下關於事件攔截處理機制的基本知識。
android 開發 View _14 MotionEvent和事件處理詳解,與實踐自定義滑動條View
MotionEvent MotionEvent物件是與使用者觸控相關的時間序列,該序列從使用者首次觸控式螢幕幕開始,經歷手指在螢幕表面的任何移動,直到手指離開螢幕時結束。手指的初次觸控(ACTION_DOWN操作),滑動(ACTION_MOVE操作)和擡起(ACTION
Android開發知識(八):Android事件處理機制:事件分發、傳遞、攔截、處理機制的原理分析(中)
在本章節中,我們重點談論一下onTouch、onClick、onLongClick三個方法被回撥的過程。 在上一篇文章中,我們談到關於為View新增一個點選事件SetOnClickListener後,就可以通過回撥onClick方法來實現事件的響應
android 滑動事件衝突解決 Touch事件處理機制
android中的事件型別分為按鍵事件和螢幕觸控事件,Touch事件是螢幕觸控事件的基礎事件,有必要對它進行深入的瞭解。 一個最簡單的螢幕觸控動作觸發了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->AC
android onTouchEvent 左右手勢滑動事件處理
要實現手指在螢幕上左右滑動的事件需要例項化物件GestureDetector,new GestureDetector(MainActivity.this,onGestureListener);首先實現監聽物件GestureDetector.OnGestureListener
一文讀懂 Android TouchEvent 事件分發、攔截、處理過程
什麼是事件?事件是使用者觸控手機螢幕,引起的一系列TouchEvent,包括ACTION_DOWN、ACTION_MOVE、ACTION_UP、ACTION_CANCEL等,這些action組合後變成點選事件、長按事件等。 在這篇文章中,用打Log測試的方法來了解Android TouchEvent 事件分發
Android — 長按ListView 利用上下文菜單(ActionMode) 進行批量事件處理
改變 out thread miss static server ann break 我們 好久沒寫博客拉``````` 近期最終略微閑一點了``````` 無聊拿手機清理短信。發現批量事件的處理還是挺管用的`````` 那麽自己也來山寨一記看看效果吧````
Android學習筆記(36):Android的兩種事件處理方式
post gravity cal log 基於 處理方法 hang mil 重寫 Android提供了兩種事件處理的方式:基於回調的事件處理 和 基於監聽的事件處理。 我們來說的easy理解一點: (1)基於回調的事件處理就是繼承GUI組件,並重寫該組件的
Android零基礎入門第66節:RecyclerView點擊事件處理
系統 ava oid 文章 click事件 需要 spin 圖像 line 前面兩期學習了RecyclerView的簡單使用,並為其item添加了分割線。在實際運用中,無論是List還是Grid效果,基本都會伴隨著一些點擊操作,那麽本期就來一起學習RecyclerVi
Android 自定義組件 事件處理
items int ems set rect 獲取 控件 pan highlight 以點擊事件為例: 覆寫方法: public boolean dispatchTouchEvent(MotionEvent event); 可以從MotionEvent 獲取事件坐標,
Android熱插拔事件處理流程--Vold
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Android開發指南-使用者介面-事件處理
處理使用者介面事件 Handling UI Events 在 Android 上,不止一個途徑來偵聽使用者和應用程式之間互動的事件。對於使用者介面裡的事件,偵聽方法就是從與使用者互動的特定檢視物件截獲這些事件。檢視類提供了相應的手段。 在各種用來組建佈局的檢視類裡面,你可能會
Android完美處理RecyclerView實現item條目點選事件處理
前言: RecyclerView並沒有像ListView那樣提供了OnItemClick,OnItemLongClick等事件回撥介面,所以,我們需要自己寫介面去進行實現。 正題 ①、建立介面類OnRecyclerViewClickListener /** * Recy