app要加入右滑返回上个界面的功能,百度了一下,发现这个库不错,https://github.com/ikew0ng/SwipeBackLayout,于是集成到app里面。
在跑这个demo的时候,发现返回的时候看到的是桌面,并非上个界面,百度一下,发现很多人遇到这个问题,于是加入这个代码到要返回的activity的主题里即可
<item name= "android:windowIsTranslucent" >true </item>但这个库支持右滑返回的接触面只在左侧,虽然有setEdgeSize设置宽度,但好像不是很有效,百度一下
//http://blog.csdn.net/eiuly/article/details/46472783
private int getEdgeTouched(int x, int y) {
result = EDGE_LEFT;//这样每次都是全屏左滑删除
return result;
}
这样果然可以全屏右滑返回了,但在测试的时候发现某些界面用到了popupwidow,弹框的时候设置了其他地方变黑的遮罩,导致整个activity的界面不见了,百度无果,于是只能把popupwindow改成alertdialog来解决了。
改好后看起来一切都OK了,但测试的时候又发现一个问题,5.5寸屏幕的手机操作起来还可以,但在我新买的小米5(5.15寸)黑色版本上操作起来的时候,在有垂直滚动的界面单手滚动界面的时候很容易触发侧滑操作,这就尴尬了。百度无果,于是只能自己解决了。
查看SwipeBackLayout代码,有onInterceptTouchEvent事件分发函数,找来笔记本,画了一下操作手势图。
开始的时候根据垂直距离与水平的滑动距离来判断事件的拦截,但效果一点也不理想,于是想到用角度来判断胡奥的滑动的意图。两点与XY轴形成的三角形的夹角如果大于45°(我自己想的)就判定为垂直滚动的,否则就是侧滑返回。理论有了就敲代码,幸好以前算过三角函数,计算两点的角度代码
float a = xDistance;//a边
float b = yDistance;//b边
double c = Math.sqrt(a * a + b * b);//c边,斜边
double Q = Math.asin(b / c);//a、b边的夹角度数(Q / Math.PI * 180这个才是人类常用的角度)
<pre style="font-family: Consolas; font-size: 11.3pt; background-color: rgb(255, 255, 255);">于是加入判断
测试一下代码,发现可行。if (Math.abs(Q / Math.PI * 180) > 45 && mDragState == STATE_IDLE && 0 != xDistance) { return false; }
附上ViewDragHelper文件修改地方的代码
// 滑动距离及坐标 private float xDistance, yDistance, xLast, yLast; /** * Check if this event as provided to the parent view's * onInterceptTouchEvent should cause the parent to intercept the touch * event stream. * * @param ev MotionEvent provided to onInterceptTouchEvent * @return true if the parent view should return true from * onInterceptTouchEvent */ public boolean shouldInterceptTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); final int actionIndex = MotionEventCompat.getActionIndex(ev); if (action == MotionEvent.ACTION_DOWN) { // Reset things for a new event stream, just in case we didn't get // the whole previous stream. cancel(); } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); switch (action) { case MotionEvent.ACTION_DOWN: { xDistance = yDistance = 0f; xLast = ev.getX(); yLast = ev.getY(); final float x = ev.getX(); final float y = ev.getY(); final int pointerId = MotionEventCompat.getPointerId(ev, 0); saveInitialMotion(x, y, pointerId); final View toCapture = findTopChildUnder((int) x, (int) y); // Catch a settling view if possible. if (toCapture == mCapturedView && mDragState == STATE_SETTLING) { tryCaptureViewForDrag(toCapture, pointerId); } final int edgesTouched = mInitialEdgeTouched[pointerId]; if ((edgesTouched & mTrackingEdges) != 0) { mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); } break; } case MotionEventCompat.ACTION_POINTER_DOWN: { final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); final float x = MotionEventCompat.getX(ev, actionIndex); final float y = MotionEventCompat.getY(ev, actionIndex); saveInitialMotion(x, y, pointerId); // A ViewDragHelper can only manipulate one view at a time. if (mDragState == STATE_IDLE) { final int edgesTouched = mInitialEdgeTouched[pointerId]; if ((edgesTouched & mTrackingEdges) != 0) { mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); } } else if (mDragState == STATE_SETTLING) { // Catch a settling view if possible. final View toCapture = findTopChildUnder((int) x, (int) y); if (toCapture == mCapturedView) { tryCaptureViewForDrag(toCapture, pointerId); } } break; } case MotionEvent.ACTION_MOVE: { final float curX = ev.getX(); final float curY = ev.getY(); xDistance += Math.abs(curX - xLast); yDistance += Math.abs(curY - yLast); xLast = curX; yLast = curY; float a = xDistance;//a边 float b = yDistance;//b边 double c = Math.sqrt(a * a + b * b);//c边,斜边 double Q = Math.asin(b / c);//a、b边的夹角度数(Q / Math.PI * 180这个才是人类常用的角度) if (Math.abs(Q / Math.PI * 180) > 45 && mDragState == STATE_IDLE && 0 != xDistance) { Log.i("xiang:", "xDistance-" + xDistance + " yDistance-" + yDistance + "角度-"+Q / Math.PI * 180); return false; } // First to cross a touch slop over a draggable view wins. Also // report edge drags. final int pointerCount = MotionEventCompat.getPointerCount(ev); for (int i = 0; i < pointerCount; i++) { final int pointerId = MotionEventCompat.getPointerId(ev, i); final float x = MotionEventCompat.getX(ev, i); final float y = MotionEventCompat.getY(ev, i); final float dx = x - mInitialMotionX[pointerId]; final float dy = y - mInitialMotionY[pointerId]; reportNewEdgeDrags(dx, dy, pointerId); if (mDragState == STATE_DRAGGING) { // Callback might have started an edge drag break; } final View toCapture = findTopChildUnder((int) x, (int) y); if (toCapture != null && checkTouchSlop(toCapture, dx, dy) && tryCaptureViewForDrag(toCapture, pointerId)) { break; } } saveLastMotion(ev); break; } case MotionEventCompat.ACTION_POINTER_UP: { final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); clearMotionHistory(pointerId); break; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { cancel(); break; } } return mDragState == STATE_DRAGGING; }