Android 滑动,拦截事件处理

小咪咪 2022-08-09 17:45 374阅读 0赞

之前一片文章 初略的讲了一些关于事件传递的基本内容,现在这片博客,

主要是具体去运用事件传递拦截的相关内容,

ok 具体要实现的目标就是,

view 能够正常的吃掉点击事件, 但是如果是滑动事件时, 则是父View 来处理来滑动另一个View

基本原理就是

在View group中得onInterceptTouchEvent 方法中判断是否是滑动,

如果是滑动,那么就返回true 自身去消费滑动事件,

还需要注意的是, 在处理滑动事件的时候需要注意 两个手指滑动的情况

即 另一个手指按下也能够继续滑动,

不多说了上代码:

  1. /**
  2. * 只处理 纵向滑动事件, 其他事件不做 处理
  3. */
  4. public class CustomScrollViewGroup extends RelativeLayout {
  5. public static final String TAG = "CustomScrollViewGroup";
  6. public CustomScrollViewGroup(Context context) {
  7. super(context);
  8. init();
  9. }
  10. public CustomScrollViewGroup(Context context, AttributeSet attrs) {
  11. super(context, attrs);
  12. init();
  13. }
  14. public CustomScrollViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
  15. super(context, attrs, defStyleAttr);
  16. init();
  17. }
  18. private static final int MIN_DISTANCE_FOR_FLING = 25; // dips
  19. private OnScrollListener mOnScrollListener;
  20. private int mTouchSlop;
  21. protected VelocityTracker mVelocityTracker;
  22. private int mMinimumVelocity;
  23. private int mMaximumVelocity;
  24. /**
  25. * Position of the last motion event.
  26. */
  27. private float mLastMotionX;
  28. private float mLastMotionY;
  29. private float mInitialMotionY, mInitialMotionX;
  30. protected int mActivePointerId = INVALID_POINTER;
  31. private static final int INVALID_POINTER = -1;
  32. private boolean mIsUnableToDrag = false;
  33. private int mFlingDistance;
  34. private boolean mIsBeingDragged = false;
  35. boolean mScrollToEnd = false;//标记View是否已经完全消失,OvershootInterpolator回弹时间忽略
  36. private boolean mQuickReturn = false;
  37. boolean isTouchOnRecycleView = false;
  38. private void init() {
  39. final ViewConfiguration configuration = ViewConfiguration.get(getContext());
  40. mTouchSlop = configuration.getScaledTouchSlop();
  41. mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
  42. mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
  43. final float density = getContext().getResources().getDisplayMetrics().density;
  44. mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
  45. }
  46. @Override
  47. protected void onAttachedToWindow() {
  48. super.onAttachedToWindow();
  49. int childCount = getChildCount();
  50. for (int i = 0; i < childCount; i++) {
  51. View child = getChildAt(i);
  52. }
  53. }
  54. @Override
  55. public boolean onInterceptTouchEvent(MotionEvent ev) {
  56. LogUtil.d(TAG, "onInterceptTouchEvent ev = " + ev.getAction());
  57. final int action = ev.getAction();
  58. if (action == MotionEvent.ACTION_CANCEL
  59. || action == MotionEvent.ACTION_UP
  60. || (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) {
  61. endDrag();
  62. return false;
  63. }
  64. switch (action & MotionEventCompat.ACTION_MASK) {
  65. case MotionEvent.ACTION_DOWN:
  66. // Remember where the motion event started
  67. int index = MotionEventCompat.getActionIndex(ev);
  68. mActivePointerId = MotionEventCompat.getPointerId(ev, index);
  69. if (mActivePointerId == INVALID_POINTER)
  70. break;
  71. mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, index);
  72. mInitialMotionY = mLastMotionY = MotionEventCompat.getY(ev, index);
  73. mIsBeingDragged = false;
  74. mIsUnableToDrag = false;
  75. break;
  76. case MotionEvent.ACTION_MOVE:
  77. final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
  78. if (mActivePointerId == INVALID_POINTER) {
  79. break;
  80. }
  81. final float currentY = MotionEventCompat.getY(ev, activePointerIndex);
  82. final float deltaY = mLastMotionY - currentY;
  83. determineDrag(ev);
  84. break;
  85. }
  86. if (!mIsBeingDragged) {
  87. if (mVelocityTracker == null) {
  88. mVelocityTracker = VelocityTracker.obtain();
  89. }
  90. mVelocityTracker.addMovement(ev);
  91. }
  92. return mIsBeingDragged || mQuickReturn;
  93. }
  94. private int getPointerIndex(MotionEvent ev, int id) {
  95. int activePointerIndex = MotionEventCompat.findPointerIndex(ev, id);
  96. if (activePointerIndex == -1)
  97. mActivePointerId = INVALID_POINTER;
  98. return activePointerIndex;
  99. }
  100. private int mScrollY = 0;
  101. @Override
  102. public boolean onTouchEvent(MotionEvent ev) {
  103. LogUtil.d(TAG, "onTouchEvent ev = " + ev.getAction());
  104. if (mVelocityTracker == null) {
  105. mVelocityTracker = VelocityTracker.obtain();
  106. }
  107. mVelocityTracker.addMovement(ev);
  108. final int action = ev.getAction();
  109. switch (action & MotionEventCompat.ACTION_MASK) {
  110. case MotionEvent.ACTION_DOWN:
  111. // Remember where the motion event started
  112. int index = MotionEventCompat.getActionIndex(ev);
  113. mActivePointerId = MotionEventCompat.getPointerId(ev, index);
  114. mLastMotionY = mInitialMotionY = ev.getY();
  115. mLastMotionX = mInitialMotionX = ev.getX();
  116. break;
  117. case MotionEvent.ACTION_MOVE:
  118. if (!mIsBeingDragged) {
  119. determineDrag(ev);
  120. if (mIsUnableToDrag)
  121. return false;
  122. }
  123. if (mIsBeingDragged) {
  124. final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
  125. if (mActivePointerId == INVALID_POINTER)
  126. break;
  127. final float y = MotionEventCompat.getY(ev, activePointerIndex);
  128. final float deltaY = mLastMotionY - y;
  129. mLastMotionY = y;
  130. float oldScrollY = mScrollY;
  131. float scrollY = oldScrollY + deltaY;
  132. mLastMotionX += scrollY - (int) scrollY;
  133. mScrollY = (int) scrollY;
  134. if (mOnScrollListener != null) {
  135. mOnScrollListener.onScroll(0, deltaY);
  136. }
  137. }
  138. break;
  139. case MotionEvent.ACTION_UP:
  140. case MotionEvent.ACTION_CANCEL:
  141. if (mIsBeingDragged) {
  142. final VelocityTracker velocityTracker = mVelocityTracker;
  143. velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
  144. int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(velocityTracker, mActivePointerId);
  145. final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
  146. if (mActivePointerId != INVALID_POINTER) {
  147. final float y = MotionEventCompat.getY(ev, activePointerIndex);
  148. final int totalDelta = (int) (y - mInitialMotionY);// doww -> up detal
  149. if (Math.abs(totalDelta) > mFlingDistance && Math.abs(initialVelocity) > mMinimumVelocity) {
  150. if (initialVelocity > 0 && totalDelta > 0) {
  151. // 向下滑
  152. if (mOnScrollListener != null) {
  153. mOnScrollListener.onFling(false);
  154. }
  155. } else if (initialVelocity < 0 && totalDelta < 0) {
  156. // 向上滑
  157. if (mOnScrollListener != null) {
  158. mOnScrollListener.onFling(true);
  159. }
  160. } else {
  161. if (mOnScrollListener != null) {
  162. mOnScrollListener.onScrollOver();
  163. }
  164. }
  165. } else {
  166. if (mOnScrollListener != null) {
  167. mOnScrollListener.onScrollOver();
  168. }
  169. // 不是 fling 最后是 划上 还是划下 外面判断
  170. }
  171. }
  172. mActivePointerId = INVALID_POINTER;
  173. endDrag();
  174. }
  175. break;
  176. case MotionEventCompat.ACTION_POINTER_DOWN: {
  177. final int indexx = MotionEventCompat.getActionIndex(ev);
  178. mLastMotionY = MotionEventCompat.getY(ev, indexx);
  179. mLastMotionX = MotionEventCompat.getX(ev, indexx);
  180. mActivePointerId = MotionEventCompat.getPointerId(ev, indexx);
  181. break;
  182. }
  183. case MotionEventCompat.ACTION_POINTER_UP:
  184. int pointerIndex = getPointerIndex(ev, mActivePointerId);
  185. if (mActivePointerId == INVALID_POINTER)
  186. break;
  187. mLastMotionY = MotionEventCompat.getY(ev, pointerIndex);
  188. mLastMotionX = MotionEventCompat.getX(ev, pointerIndex);
  189. break;
  190. }
  191. return true;
  192. }
  193. private void determineDrag(MotionEvent ev) {
  194. final int activePointerId = mActivePointerId;
  195. final int pointerIndex = getPointerIndex(ev, activePointerId);
  196. if (activePointerId == INVALID_POINTER || pointerIndex == INVALID_POINTER)
  197. return;
  198. final float x = MotionEventCompat.getX(ev, pointerIndex);
  199. final float dx = x - mLastMotionX;
  200. final float xDiff = Math.abs(dx);
  201. final float y = MotionEventCompat.getY(ev, pointerIndex);
  202. final float dy = y - mLastMotionY;
  203. final float yDiff = Math.abs(dy);
  204. if (yDiff > mTouchSlop && yDiff > xDiff) {
  205. startDrag();
  206. mLastMotionX = x;
  207. mLastMotionY = y;
  208. } else if (xDiff > mTouchSlop) {
  209. mIsUnableToDrag = true;
  210. }
  211. }
  212. // 开始滑动
  213. private void startDrag() {
  214. mIsBeingDragged = true;
  215. mQuickReturn = false;
  216. mScrollToEnd = false;
  217. }
  218. private void endDrag() {
  219. mQuickReturn = false;
  220. mIsBeingDragged = false;
  221. mIsUnableToDrag = false;
  222. mActivePointerId = INVALID_POINTER;
  223. if (mVelocityTracker != null) {
  224. mVelocityTracker.recycle();
  225. mVelocityTracker = null;
  226. }
  227. }
  228. public void setOnScrollListener(OnScrollListener onScrollListener) {
  229. mOnScrollListener = onScrollListener;
  230. }
  231. public interface OnScrollListener {
  232. void onScroll(float distanceX, float distanceY);
  233. void onFling(boolean isFlingUp);
  234. void onScrollOver();
  235. }
  236. }

上面的是最主要的ViewGroup

下面在来看看 activity 中得代码

  1. public class MainActivity extends AppCompatActivity {
  2. public static final String TAG = "MainActivity";
  3. Button mButton;
  4. View mView;
  5. CustomScrollViewGroup mCustomScrollViewGroup;
  6. int maxTranY;
  7. float currentTransY = 0;
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. mButton = (Button) findViewById(R.id.btn);
  13. mView = findViewById(R.id.scrolledView);
  14. mCustomScrollViewGroup = (CustomScrollViewGroup) findViewById(R.id.customscrollviewgroup);
  15. maxTranY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 300, getResources().getDisplayMetrics());
  16. mButton.setOnClickListener(new View.OnClickListener() {
  17. @Override
  18. public void onClick(View v) {
  19. Toast.makeText(MainActivity.this, "click btn", Toast.LENGTH_SHORT).show();
  20. }
  21. });
  22. mCustomScrollViewGroup.setOnScrollListener(new CustomScrollViewGroup.OnScrollListener() {
  23. /**
  24. * 滑动 的箭头
  25. * @param distanceX 向左滑动 为正
  26. * @param distanceY 向上滑动 为正
  27. */
  28. @Override
  29. public void onScroll(float distanceX, float distanceY) {
  30. if (isAnimating) {
  31. return;
  32. }
  33. currentTransY = currentTransY - distanceY;
  34. if (currentTransY < -maxTranY) {
  35. currentTransY = -maxTranY;
  36. }
  37. if (currentTransY > 0) {
  38. currentTransY = 0;
  39. }
  40. mView.setTranslationY(currentTransY);
  41. LogUtil.d(TAG, "onScroll distanceX = " + distanceX + " , distanceY = " + distanceY + ", currentTransY = " + currentTransY);
  42. }
  43. /**
  44. * 快速滑动的回调
  45. * @param isFlingUp 是否是向上快速滑动
  46. */
  47. @Override
  48. public void onFling(boolean isFlingUp) {
  49. if (isAnimating) {
  50. return;
  51. }
  52. LogUtil.d(TAG, "onFling isFlingUp = " + isFlingUp);
  53. if (isFlingUp) {
  54. animatorScrollUp();
  55. } else {
  56. animatorScrollDowm();
  57. }
  58. }
  59. /**
  60. * 滑动结束的监听
  61. */
  62. @Override
  63. public void onScrollOver() {
  64. if (isAnimating) {
  65. return;
  66. }
  67. LogUtil.d(TAG, "onScrollOver");
  68. if (currentTransY < -maxTranY / 2) {// 向上滑超过了 1/2
  69. animatorScrollUp();
  70. } else {
  71. animatorScrollDowm();
  72. }
  73. }
  74. });
  75. }
  76. boolean isAnimating = false;
  77. private void animatorScrollUp() {
  78. ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "TranslationY", mView.getTranslationY(), -maxTranY);
  79. objectAnimator.setDuration(300);
  80. isAnimating = true;
  81. objectAnimator.addListener(new AnimatorListenerAdapter() {
  82. @Override
  83. public void onAnimationEnd(Animator animation) {
  84. super.onAnimationEnd(animation);
  85. currentTransY = -maxTranY;
  86. isAnimating = false;
  87. }
  88. });
  89. objectAnimator.start();
  90. }
  91. private void animatorScrollDowm() {
  92. ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mView, "TranslationY", mView.getTranslationY(), 0);
  93. objectAnimator.setDuration(300);
  94. isAnimating = true;
  95. objectAnimator.addListener(new AnimatorListenerAdapter() {
  96. @Override
  97. public void onAnimationEnd(Animator animation) {
  98. super.onAnimationEnd(animation);
  99. currentTransY = 0;
  100. isAnimating = false;
  101. }
  102. });
  103. objectAnimator.start();
  104. }
  105. }

源码地址 : https://github.com/crianzy/AndroidDemo/tree/master/TouchEventClickScrollDemo

发表评论

表情:
评论列表 (有 0 条评论,374人围观)

还没有评论,来说两句吧...

相关阅读

    相关 android滑动事件监听

    android中滑动事件是非常常用的,无论是游戏中还是普通的APP中应用都非常广泛,下面来看下他的代码是如何实现的,其代码如下 private void touchl

    相关 Android拦截html链接事件

    在一个大的Android项目中,由于客户端来不及更新和实现,经常会内嵌一些网页(在一些大型的互联网公司,PC的产品总是跑在客户端的前面),比如活动页面,通常可以内嵌用html5

    相关 Android事件处理

      UI编程通常都会伴随事件处理,Android也不例外,它提供了两种方式的事件处理:基于回调的事件处理和基于监听器的事件处理。 对于基于监听器的事件处理而言,主要