书接前文 《Android使用LayoutParams属性进行左右侧滑动画》
其中使用的是onTouchEvent的重写,虽然示例看起来不错,但将其中button换为ListView时就不尽人意了,父子间事件有冲突
本例重写dispatchTouchEvent,这是交互事件首先被处理的方法。
容器类View的事件传递:dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent
控件类View的事件传递:dispatchTouchEvent -> onTouchEvent
手指按下
首先记录按下的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@Override public boolean dispatchTouchEvent(MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); switch (event.getAction()) { //--- 手指按下,down -------------------------------------------------------------- case MotionEvent.ACTION_DOWN: xDown = event.getRawX(); yDown = event.getRawY(); // 无论是否已经侧滑,这个得到的都是手指和本布局左边线的距离 paramsLeftMargin = (int) (xDown - contentParams.leftMargin); paramsRightMargin = (int) (contentParams.leftMargin + xDown); Log.e("sst", "xDown:" + xDown + ", yDown:" + yDown); break; |
手指滑动
手指滑动的过程不断的执行ACTION_MOVE事件。当第一个MOVE事件执行时,根据手指在y轴和x轴上滑动距离的大小确定属于上下滑动还是左右滑动。
如果是上下滑动,和侧滑动画无关,下发事件的处理;否则作为侧滑动画处理并拦截。
同时处理的还有初始左右滑继而上下滑的事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
//--- 手指滑动,move -------------------------------------------------------------- case MotionEvent.ACTION_MOVE: xMove = event.getRawX(); yMove = event.getRawY(); int distanceX = (int) (xMove - xDown); // 负数:向左滑,正数:向右滑 int distanceY = (int) (yMove - yDown); // 负数:向上滑,正数:向下滑 if(isFirstMove){ // !!!说明:如果手指上下滑动距离的n倍,大于左右滑动距离,那么,下发给子View处理 // 否则就当做侧滑事件处理。处理了要return true !!!!!!! if(Math.abs(distanceY)*1.5 > Math.abs(distanceX)){ isUpDown = true; // ok,手指做的是上下滑动 super.dispatchTouchEvent(event); } Log.e("sst", "xMove:" + xMove + ", yMove:" + yMove); isFirstMove = false; } else { // 继续滑,初始是上下滑动的话,下发。处理了手指按在上下滑继而又左右滑 if (isUpDown) return super.dispatchTouchEvent(event); // 如果向左滑的 if (distanceX <= 0) { // 如果已经滑开 if (isOpen) { // 手指滑动过程中的位置减去和边线的距离就是边线的目标位置。滑动中保持手指和边线距离不变 contentParams.leftMargin = (int) (xMove - paramsLeftMargin); contentParams.rightMargin = (int) (xMove - paramsRightMargin); // 如果向左滑的太多 if (contentParams.leftMargin < 0) { contentParams.leftMargin = 0; contentParams.rightMargin = 0; } } else { contentParams.leftMargin = 0; contentParams.rightMargin = 0; } setLayoutParams(contentParams); } // 如果向右滑动 else if (distanceX > 0) { // 如果尚未滑开 if (!isOpen) { contentParams.leftMargin = distanceX; // 负数,绝对值即向右移动的距离 contentParams.rightMargin = -distanceX; // 如果移动太多 if (contentParams.leftMargin > contentWidth - contentWidth/4) { contentParams.leftMargin = contentWidth - contentWidth/4; contentParams.rightMargin = 2 * contentWidth - contentWidth/4; } } else { contentParams.leftMargin = contentWidth - contentWidth/4; contentParams.rightMargin = 2 * contentWidth - contentWidth/4; } setLayoutParams(contentParams); } return true; // 本布局处理侧滑事件,不再下发 } break; |
手指拿起
手指拿起时应该判断是不是“点击”事件,也就是从按下到拿起手指的移动距离x、y都不足以触发滑动事件。这种情况也不足以侧滑,所以下发即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
//--- 手指拿起,up -------------------------------------------------------------- case MotionEvent.ACTION_UP: xUp = event.getRawX(); yUp = event.getRawY(); int upDistanceX = (int) (xUp - xDown); // 手指拿起后相对于按下时的距离。正数:向右,负数:向左 int upDistanceY = (int) (yUp - yDown); // 手指拿起后相对于按下时的距离。正数:向下,负数:向上 // 如果按下(可能会稍稍指头有点晃动)迅速拿起,相当于点击屏幕。此时没有滑动 if(Math.abs(upDistanceX) < touchSlop && Math.abs(upDistanceY) < touchSlop){ isUpDown = false; return super.dispatchTouchEvent(event); } // 手指拿起,侧滑要么关要么开,无所谓。下一次的第一次滑动状态设为开 isFirstMove = true; // 上下滑动时没有侧滑动作,不必复位处理。直接下发 if (isUpDown){ isUpDown = false; super.dispatchTouchEvent(event); } else { if (Math.abs(upDistanceX) >= touchSlop) { // 如果手指是向右滑动的,布局还没滑开 if (upDistanceX > 0 && !isOpen) { mVelocityTracker.computeCurrentVelocity(1000); // 计算1秒内速率 int velocity = Math.abs((int) mVelocityTracker.getXVelocity()); // x轴速度 // 如果滑动距离有效,或速度够快 if ( upDistanceX > contentWidth/5 || velocity > SNAP_VELOCITY) { // 向右移动 contentParams.leftMargin = contentWidth - contentWidth/4; contentParams.rightMargin = 2 * contentWidth - contentWidth/4; setLayoutParams(contentParams); isOpen = true; } // 如果 else { contentParams.leftMargin = 0; contentParams.rightMargin = 0; setLayoutParams(contentParams); } } else if (upDistanceX < 0 && isOpen) { mVelocityTracker.computeCurrentVelocity(1000); int velocity = Math.abs((int) mVelocityTracker.getXVelocity()); if (Math.abs(upDistanceX) > contentWidth/5 || velocity > SNAP_VELOCITY) { contentParams.leftMargin = 0; contentParams.rightMargin = 0; setLayoutParams(contentParams); isOpen = false; } else { contentParams.leftMargin = contentWidth - contentWidth/4; contentParams.rightMargin = 2 * contentWidth - contentWidth/4; setLayoutParams(contentParams); } } } else if (Math.abs(upDistanceX) < touchSlop) { // 当手指按下向左滑又向右滑回来,不足以触发事件时 if(isOpen){ contentParams.leftMargin = contentWidth - contentWidth/4; contentParams.rightMargin = 2 * contentWidth - contentWidth/4; setLayoutParams(contentParams); } else { contentParams.leftMargin = 0; contentParams.rightMargin = 0; setLayoutParams(contentParams); } } // 重置速度追踪器 mVelocityTracker.recycle(); mVelocityTracker = null; return true; } break; } // switch 结束 return super.dispatchTouchEvent(event); } // dispatchTouchEvent() 结束 |
提供项目包:注意为了上传方便android-support-v4.jar删除了,导入后记得替换。同时重写build project。
[download id="1687"]
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/1686.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设