Android 右滑返回实战

Android 右滑返回实战

我们可以看到类似QQ移动端的聊天界面、QQ空间的右滑返回比较支持单手操作,给我们短时间快速切换页面浏览信息提供了很大帮助,比较适合需要简洁操作的社交软件。当然也不是所有软件都适合右滑返回,但是今天刚好遇到一些问题,也有一些相关点子,还没查关于QQ右滑返回是如何实现的,我就谈谈我的想法与实践。


首先从MotionEvent入手

想要获得用户触摸操作,或者获得用户的手势,首先想到的就是通过某个View来获取用户的手势。 所以我们第一步就是自定义一个CustomLinearLayout继承自LinearLayout,并重写其中的onInterceptTouchEvent 或者 dispatchTouchEvent 或者onTouchEvent

public class MyLayout1 extends LinearLayout {

    public MyLayout1(Context context, AttributeSet attrs){
        super(context,attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev){
        Log.d("MyTAG","Layout1 | onInterceptTouchEvent --> "+ TestUtil.getString(ev.getAction()));
        return false;//拦截
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event){
        Log.d("MyTAG","Layout1 | dispatchTouchEvent --> "+ TestUtil.getString(event.getAction()));
        return super.dispatchTouchEvent(event);
    }
}

我们可以通过重写的这些方法获得传到我们自定义的Layout上的触摸动作,既然拿到了动作,那么我们就可以通过VelocityTracker来获得滑动速度,进而判断用户目的是上下滑动还是右滑返回,想法很充分,我们先看看能否获取到MotionEvent, 以下是MainActivity的布局文件

<?xml version="1.0" encoding="utf-8"?>
<com.fyTu.tempdemo.MyLayout1 xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/myLayout1">

</com.fyTu.tempdemo.MyLayout1>

我们运行一下看看打出来的Log

D/MyTAG: Layout1 | dispatchTouchEvent --> ACTION_DOWN

结果我们发现只有这么一个孤单单的Log,那么ACTION_MOVE到哪去了呢?猜测应该是传下来某个时刻被消费了,截断了。我们暂时不考虑,想想还有什么办法可以获取手势?
(我记得之前这么写是可以获取到ACTION_MOVE的,但是具体拿出来用的时候发现无效了,不好说,就按照获取不到ACTION_MOVE的情况接着往下走,如果你是获取得到的,那么就更灵活一些)

除了自定义View,还有什么途径可以获取到手势呢?

参考:https://blog.csdn.net/weixin_43093006/article/details/89414710 我们记得动作是从Window传到Activity的,也就是在我们的布局文件这些控件拿到动作之前,应该是Activity先获取到动作,那么我们如何通过Activity拿到动作呢?
我们在Activity中加入这段代码,dispatchTouchEvent方法是Activity分发事件的方法,有不清楚事件分发流程的可参考上文给出的博客链接

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("MyTAG","Activity | onInterceptTouchEvent --> "+ TestUtil.getString(ev.getAction()));
        return super.dispatchTouchEvent(ev);
    }

这里面的TestUtil是为了方便直接打出动作的

public class TestUtil {
    private static String[] actions = {"ACTION_DOWN","ACTION_UP","ACTION_MOVE","ACTION_CANCEL","ACTION_OUTSIDE","ACTION_POINTER_DOWN","ACTION_POINTER_UP"};
    public static String getString(int action){
        if(action >= 0 && action <=6){
            return actions[action];
        }else {
            return "you have no luck to see others";
        }
    }
}

再运行一下,你会发现我们从Activity中获取到了动作
日志打印如下

Activity | onInterceptTouchEvent --> ACTION_DOWN
 Layout1 | dispatchTouchEvent --> ACTION_DOWN
 Layout1 | onInterceptTouchEvent --> ACTION_DOWN
  Activity | onInterceptTouchEvent --> ACTION_MOVE
   Activity | onInterceptTouchEvent --> ACTION_MOVE
   Activity | onInterceptTouchEvent --> ACTION_UP

通过日志我们也能很清楚的发现:活动,显然在我们布局文件中的根View之前就拿到动作。而且还完整的拿到了全套动作,从手指按下到移动再到抬起。

那么我们接下来就是实现右滑返回了,思路和之前一样:获取手势,判断速度。

这里直接贴代码:

private VelocityTracker mVelocityTracker = null;
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("MyTAG","Activity | onInterceptTouchEvent --> "+ TestUtil.getString(ev.getAction()));
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;

            case MotionEvent.ACTION_MOVE:// 移动的时候
                break;

            case MotionEvent.ACTION_UP:
                //1000是1000毫秒的意思,即获取每秒的速率
                mVelocityTracker.computeCurrentVelocity(1000);
                //0是初始数据,
                if((Math.abs(mVelocityTracker.getXVelocity(0)) -2* Math.abs(mVelocityTracker.getYVelocity(0)))>0 && mVelocityTracker.getXVelocity()>400){
                	finish();
                }
                break;
        }
        mVelocityTracker.addMovement(ev);
        return super.dispatchTouchEvent(ev);
    }

这里我要解释一下mVelocityTracker.getXVelocity(0)的0是什么意思。getXVelocity()中参数是PointerId,可以理解我们手指触摸到屏幕的时候产生的点的id,我们可能有多个手指触摸屏幕,那么PointerId就会有 0,1,2,3甚至更多,但是运行到这一步就至少会有一个手指触摸,如果这个手指不抬起,对应的PointerId代表的屏幕上的点就是它。

(如果A手指按下,A触摸点对应的PointerId是0,A还在按下状态时候,B手指按下,B触摸点对应的PointerId就是1。 0和1这两个PointerId都对应着A、B的触摸点。但是某个时刻,A手指抬起,B仍然按下状态,这个时候PointerId 0 就顺延指向B的(A之后触摸屏幕的)触摸点,PointerId 1 也顺延,但是没有指向了(B的触摸点已经被0指向))

此外,代码中通过判断手势是偏向右滑还是偏向上下滑的判断,我个人是通过x和y的移动距离,偷懒就直接用了速度代替x和y,在我调试几次以后我发现如代码中所示的判断还算过的去,大家有兴趣可以去查一查QQ等其他软件的类似判断
如果判断通过,也就是用户当前是右滑手势,那么就结束当前活动。到这里我们的右滑返回就完成了。


那么我们现在就可以通过活动来进行右滑返回,那么接下来应该和我们日常开发如何接轨呢?这里由于时间关系我提一下我个人的思路:

我想到比较初级的两点:
1.把这段代码提到BaseSlideActivity这样的BaseActivity中去。
2.一个活动会管理着多个Fragment,我们也可以把Fragment放到任务栈中,通过右滑手势来关闭顶层Fragment。

原创文章 23 获赞 28 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43093006/article/details/98365331