菜鸟进阶Android Touch事件传递(四)
尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44343477
在该系列文章第四篇。我准备介绍一下viewpager的touch事件处理。
假设想了解touch和click的那些事,请浏览touch事件传递系列的第一篇http://blog.csdn.net/bingospunky/article/details/43603397
假设想了解touch事件一步一步传递的路线,请浏览touch事件传递系列的第二篇http://blog.csdn.net/bingospunky/article/details/43735497
假设想从源代码角度什么理解viewgroup的dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent怎样实现。请浏览touch事件传递系列的第二篇http://blog.csdn.net/bingospunky/article/details/44156771
源代码
代码A:boolean android.support.v4.view.ViewPager.onInterceptTouchEvent(MotionEvent ev)
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- /*
- * This method JUST determines whether we want to intercept the motion.
- * If we return true, onMotionEvent will be called and we do the actual
- * scrolling there.
- */
- final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
- // Always take care of the touch gesture being complete.
- if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
- // Release the drag.
- if (DEBUG) Log.v(TAG, "Intercept done!");
- mIsBeingDragged = false;
- mIsUnableToDrag = false;
- mActivePointerId = INVALID_POINTER;
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- return false;
- }
- // Nothing more to do here if we have decided whether or not we
- // are dragging.
- if (action != MotionEvent.ACTION_DOWN) {
- if (mIsBeingDragged) {
- if (DEBUG) Log.v(TAG, "Intercept returning true!");
- return true;
- }
- if (mIsUnableToDrag) {
- if (DEBUG) Log.v(TAG, "Intercept returning false!");
- return false;
- }
- }
- switch (action) {
- case MotionEvent.ACTION_MOVE: {
- /*
- * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
- * whether the user has moved far enough from his original down touch.
- */
- /*
- * Locally do absolute value. mLastMotionY is set to the y value
- * of the down event.
- */
- final int activePointerId = mActivePointerId;
- if (activePointerId == INVALID_POINTER) {
- // If we don't have a valid id, the touch down wasn't on content.
- break;
- }
- final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
- 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 yDiff = Math.abs(y - mInitialMotionY);
- if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
- if (dx != 0 && !isGutterDrag(mLastMotionX, dx) &&
- canScroll(this, false, (int) dx, (int) x, (int) y)) {
- // Nested view has scrollable area under this point. Let it be handled there.
- mLastMotionX = x;
- mLastMotionY = y;
- mIsUnableToDrag = true;
- return false;
- }
- if (xDiff > mTouchSlop && xDiff * 0.5f > yDiff) {
- if (DEBUG) Log.v(TAG, "Starting drag!");
- mIsBeingDragged = true;
- requestParentDisallowInterceptTouchEvent(true);
- setScrollState(SCROLL_STATE_DRAGGING);
- mLastMotionX = dx > 0 ? mInitialMotionX + mTouchSlop :
- mInitialMotionX - mTouchSlop;
- mLastMotionY = y;
- setScrollingCacheEnabled(true);
- } else if (yDiff > mTouchSlop) {
- // The finger has moved enough in the vertical
- // direction to be counted as a drag... abort
- // any attempt to drag horizontally, to work correctly
- // with children that have scrolling containers.
- if (DEBUG) Log.v(TAG, "Starting unable to drag!");
- mIsUnableToDrag = true;
- }
- if (mIsBeingDragged) {
- // Scroll to follow the motion event
- if (performDrag(x)) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }
- break;
- }
- case MotionEvent.ACTION_DOWN: {
- /*
- * Remember location of down touch.
- * ACTION_DOWN always refers to pointer index 0.
- */
- mLastMotionX = mInitialMotionX = ev.getX();
- mLastMotionY = mInitialMotionY = ev.getY();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- mIsUnableToDrag = false;
- mScroller.computeScrollOffset();
- if (mScrollState == SCROLL_STATE_SETTLING &&
- Math.abs(mScroller.getFinalX() - mScroller.getCurrX()) > mCloseEnough) {
- // Let the user 'catch' the pager as it animates.
- mScroller.abortAnimation();
- mPopulatePending = false;
- populate();
- mIsBeingDragged = true;
- requestParentDisallowInterceptTouchEvent(true);
- setScrollState(SCROLL_STATE_DRAGGING);
- } else {
- completeScroll(false);
- mIsBeingDragged = false;
- }
- if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
- + " mIsBeingDragged=" + mIsBeingDragged
- + "mIsUnableToDrag=" + mIsUnableToDrag);
- break;
- }
- case MotionEventCompat.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- break;
- }
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
- /*
- * The only time we want to intercept motion events is if we are in the
- * drag mode.
- */
- return mIsBeingDragged;
- }
代码B:boolean android.support.v4.view.ViewPager.onTouchEvent(MotionEvent ev)
- public boolean onTouchEvent(MotionEvent ev) {
- if (mFakeDragging) {
- // A fake drag is in progress already, ignore this real one
- // but still eat the touch events.
- // (It is likely that the user is multi-touching the screen.)
- return true;
- }
- if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
- // Don't handle edge touches immediately -- they may actually belong to one of our
- // descendants.
- return false;
- }
- if (mAdapter == null || mAdapter.getCount() == 0) {
- // Nothing to present or scroll; nothing to touch.
- return false;
- }
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(ev);
- final int action = ev.getAction();
- boolean needsInvalidate = false;
- switch (action & MotionEventCompat.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN: {
- mScroller.abortAnimation();
- mPopulatePending = false;
- populate();
- // Remember where the motion event started
- mLastMotionX = mInitialMotionX = ev.getX();
- mLastMotionY = mInitialMotionY = ev.getY();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- break;
- }
- case MotionEvent.ACTION_MOVE:
- if (!mIsBeingDragged) {
- final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, pointerIndex);
- final float xDiff = Math.abs(x - mLastMotionX);
- final float y = MotionEventCompat.getY(ev, pointerIndex);
- final float yDiff = Math.abs(y - mLastMotionY);
- if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
- if (xDiff > mTouchSlop && xDiff > yDiff) {
- if (DEBUG) Log.v(TAG, "Starting drag!");
- mIsBeingDragged = true;
- requestParentDisallowInterceptTouchEvent(true);
- mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
- mInitialMotionX - mTouchSlop;
- mLastMotionY = y;
- setScrollState(SCROLL_STATE_DRAGGING);
- setScrollingCacheEnabled(true);
- // Disallow Parent Intercept, just in case
- ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
- }
- // Not else! Note that mIsBeingDragged can be set above.
- if (mIsBeingDragged) {
- // Scroll to follow the motion event
- final int activePointerIndex = MotionEventCompat.findPointerIndex(
- ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, activePointerIndex);
- needsInvalidate |= performDrag(x);
- }
- break;
- case MotionEvent.ACTION_UP:
- if (mIsBeingDragged) {
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
- velocityTracker, mActivePointerId);
- mPopulatePending = true;
- final int width = getClientWidth();
- final int scrollX = getScrollX();
- final ItemInfo ii = infoForCurrentScrollPosition();
- final int currentPage = ii.position;
- final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
- final int activePointerIndex =
- MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- final float x = MotionEventCompat.getX(ev, activePointerIndex);
- final int totalDelta = (int) (x - mInitialMotionX);
- int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
- totalDelta);
- setCurrentItemInternal(nextPage, true, true, initialVelocity);
- mActivePointerId = INVALID_POINTER;
- endDrag();
- needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- if (mIsBeingDragged) {
- scrollToItem(mCurItem, true, 0, false);
- mActivePointerId = INVALID_POINTER;
- endDrag();
- needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
- }
- break;
- case MotionEventCompat.ACTION_POINTER_DOWN: {
- final int index = MotionEventCompat.getActionIndex(ev);
- final float x = MotionEventCompat.getX(ev, index);
- mLastMotionX = x;
- mActivePointerId = MotionEventCompat.getPointerId(ev, index);
- break;
- }
- case MotionEventCompat.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- mLastMotionX = MotionEventCompat.getX(ev,
- MotionEventCompat.findPointerIndex(ev, mActivePointerId));
- break;
- }
- if (needsInvalidate) {
- ViewCompat.postInvalidateOnAnimation(this);
- }
- return true;
- }
代码C:void android.support.v4.view.ViewPager.onSecondaryPointerUp(MotionEvent ev)
- private void onSecondaryPointerUp(MotionEvent ev) {
- final int pointerIndex = MotionEventCompat.getActionIndex(ev);
- final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
- if (pointerId == mActivePointerId) {
- // This was our active pointer going up. Choose a new
- // active pointer and adjust accordingly.
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
- mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
- }
总结
在这里就不想上篇文章那样分各种情况去讨论了。那样有些无聊。这里就重要点的说明一下我的理解,最后附一个我写的demo供大家參考学习。
1、viewpager处理touch的思路:不截断touch。假设touch移动满足了一定的条件,再截断touch由该viewgroup处理。
2、我们能够看到onInterceptTouchEvent和onTouchEvent方法里的方法非常相似。对于一个touch事件。这两个方法基本不会被都运行。仅仅有非常少的情况下这两个方法都会被运行。
3、viewpager有趣的现象。操作:单点操作viewpager。使viewpager响应事件,再加一个点触碰viewpager。如此不断加点,能够看到viewpager响应后加上去点的事件,这是为什么呢?代码B第108--111行已经告诉我们了,不再解释。
4、viewpager有趣的现象。操作:对于前面不不断加上去的触点,假设如今一共同拥有4个触点。如今响应第4个触点的事件,假设第4个触点抬起,那么viewpager响应哪个触点的事件呢?答案是第一个。
规律是什么呢?抬起的触点不是当前响应的。那么没影响;假设是当前响应的:假设抬起的触点的pointerIndex不是0,那么由pointerIndex最小的触点来响应,所以由第一个来响应。代码C已经非常明显告诉我们了。
假设这里你看不懂,那么你要学习一下android是怎么处理多触点事件的就会明确了。
Demo
下载地址:http://download.csdn.net/detail/u011647962/8507523
版权声明:本文博主原创文章。转载请注明出处。
菜鸟进阶Android Touch事件传递(四)的更多相关文章
- Android Touch事件传递机制 一: OnTouch,OnItemClick(监听器),dispatchTouchEvent(伪生命周期)
ViewGroup View Activity dispatchTouchEvent 有 有 有 onInterceptTouchEvent 有 无 无 onTouchEvent 有 有 有 例 ...
- Android touch 事件传递机制
前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事 ...
- Android Touch事件传递机制通俗讲解
在讲正题之前我们讲一段有关任务传递的小故事,抛砖迎玉下: 话说一家软件公司,来一个任务,分派给了开发经理去完成: 开发经理拿到,看了一下,感觉好简单,于是 开发经理:分派给了开发组长 开发组长:分派给 ...
- Android Touch事件传递机制 二:单纯的(伪生命周期)
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android Touch事件传递机制引发的血案
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38942135 关于Android Touch事件传递机制我之前也写过两篇文章,自觉得对Tou ...
- Android Touch事件传递机制详解 下
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...
- Android Touch事件传递机制具体解释 下
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...
- Android Touch事件传递机制具体解释 上
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/37961997 近期总是遇到关于Android Touch事件的问题,如:滑动冲突的问题,曾经 ...
随机推荐
- 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)
1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 908 Solved: 159 [Su ...
- CodeForces 396C 树状数组 + DFS
本主题开始看到以为段树或树状数组,但是,对于一个节点的有疑问的所有子节点的加权,这一条件被视为树的根,像 然后1号是肯定在第一层中,然后建立一个单向侧倒查,然后记录下来 其中每个节点 层,终于 两个节 ...
- 付款页面DEMO
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveHRxdWVlbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- 如何track存储过程的编译次数
原文:如何track存储过程的编译次数 转载自此处 有个script我们很熟悉,是用来去查找当前SQL Server中哪些存储过程变重编译的次数最多的: --Gives you the top 25 ...
- 于Eclipse传导C/C++配置方法开发(20140721新)
Eclipse 它是一个开源.基于Java可扩展的开发平台. 在其自己的.它只是一个框架和一组服务.对于通过插件组件构建开发环境. --从百度百科的短语. 简单的说Eclipse 是免费的开源的Jav ...
- 装双系统(win7/win8/ubuntu)问题总结
1.假设你要安装双系统,装系统是最好安装winows,然后再装ubuntu,因此,不解决它自己入选,我一般装ubuntu时刻.第一分区删除.然后用U硬盘直接安装ubuntu.在这一刻ubuntu将投入 ...
- MKMapView移动事件地图
MKMapView移动事件地图 by 吴雪莹 -(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated { ...
- struts2-dojo-plugin-2.3.1.2.jar!/struts-plugin.xml:29:119
Unable to load configuration. - bean - jar:file:/D:/code_workspace/SSHWorkSpace3/.metadata/.plugins/ ...
- 数据库文档生成工具——word2chm,SqlSpec
首先使用代码生成器可以生成word版本的数据库文档. 转成chm格式的更加小巧和方便~ SqlSpec是个好工具,可以生成所有数据库相关的信息 之后可以一键生成chm文档.
- Systrace
在构造函数,修复bug.完成代码后,你应该花一些时间来专注于应用性能.应用视频像素和运行的运行速度和流畅度影响用户体验. Android应用执行在一个共享资源的环境中,你的应用的性能会 ...