右滑结束当前界面返回上一界面,是一个很棒的交互,尤其对大屏幕手机用户。iOS原生可以完美地支持,Android原生却并未得到支持。支持右滑返回的开源项目五花八门,然而或多或少有配置麻烦、兼容适配、性能开销等问题。但是,如果你单纯想实现一个滑动返回,而不需要各种效果,就像手机QQ那样,那么请往下看。
原理
捕捉Activity触摸事件分发,判断右滑手势,结束当前界面。
一般而言,当手机触摸屏幕那一刻,首先由Activity的dispatchTouchEvent()
开始向下分发事件,各ViewGroup再分发至其子View。因此,我们重写Activity的dispatchTouchEvent()
方法,在其中判断用户是否进行了有效的右滑操作(但不能改变其固有的分发逻辑),从而结束当前Activity。
关于Android的事件分发机制不在此展开,张神的这篇博文我觉得是讲得非常通俗易懂的。
实现
为了write once, use anywhere,我们可以写到BaseActivity里,需要右滑返回的界面继承之即可。
public abstract class BaseActivity extends AppCompatActivity {
private MotionEvent mActionDownEvent;
private VelocityTracker mVelocityTracker;
......
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (mActionDownEvent != null) {
mActionDownEvent.recycle();
}
mActionDownEvent = MotionEvent.obtain(ev); // 记录按下时的事件
} else if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
// 右滑返回手势检测
int pointerId = ev.getPointerId(0);
int maximumFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity();
int minimumFlingVelocity = ViewConfiguration.get(this).getScaledMinimumFlingVelocity();
mVelocityTracker.computeCurrentVelocity(1000, maximumFlingVelocity);
final float velocityX = mVelocityTracker.getXVelocity(pointerId);
if (mActionDownEvent.getX() <= 50 // 左边缘检测,可根据需要调整,单位像素
&& ev.getX() - mActionDownEvent.getX() >= 300 // 有效触发距离,可根据需要调整,单位像素
&& Math.abs(velocityX) >= minimumFlingVelocity) {
onBackPressed(); // finish当前Activity
}
}
return super.dispatchTouchEvent(ev); // 分发控制还给Activity
}
......
@Override
protected void onDestroy() {
super.onDestroy();
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
}
}
}
没错,就这么简单!
如果想实现自由的开关滑动返回功能,只需要加一个开关参数即可:
boolean disableSlidingBack; // 在子Activity中设为true,关闭滑动返回
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (disableSlidingBack) {
return super.dispatchTouchEvent(ev);
}
// 后面不变
}
效果
图中Activity finish过渡没有使用动画,是系统自带的效果。我的系统是MIUI,部分系统过渡动画可能不是左右方向,如果考虑适配问题,可以在style里统一设置。