美文网首页
第3章 View 的事件体系

第3章 View 的事件体系

作者: SunnyGL | 来源:发表于2020-01-11 18:32 被阅读0次

总体来说本章知识点还是比较简单的,主要就是View的基础知识和事件分发,滑动冲突解决方案。

首先作者介绍了View的一些基础知识,我们了解到View是Android所有控件的基类,ViewGroup继承View,可以理解为一个控件组,其内部可以包含一系列子View。View在父容器中由top、left、 right、bottom四个属性描述自身位置,x、y、translationX和translationY属性描述View在父容器中的位移信息。MotionEvent描述View点击事件的类型,TouchSlop是系统所能识别出的被认为是滑动的最小距离。VelocityTracker用来追踪手指在View上滑动过程中的速度。GestureDetector用来辅助检测用户的单击,滑动,长按,双击等行为。Scroller用来实现View的连续滑动。

接着作者介绍了View滑动的三种实现方式。第一种为使用scrollTo/scrollBy,scrollTo和scrollBy只能改变View内容的位置而不能改变View在布局中的位置。第二种为使用动画,View动画只是对View的影像做操作,并没有真正的改变View的位置参数,属性动画则会修改View的位置参数。第三种为改变布局参数,即改变LayoutParams。

接下来作者介绍了三种连续滑动动画的实现方法,第一种使用Scroller,第二种使用动画,第三种通过一个计时器去刷新View位置。重点看下Scroller,Scroller其实并未实现真正的持续滑动动画,它只负责计算在动画运动中View的位置信息,然后将位置信息交给scrollTo方法去刷新View的位置,对View毫无引用。

下面是本章的重头戏,作者讲解了View的事件分发机制,当一个点击操作发生时,事件最先传递到当前Activity,然后交给Activity所属的Window进行分发,Window再传递到DecorView,DecorView就是当前Activity内的最顶级View,接下来就要从ViewGroup和View两个类的源码去深扒View的事件分发机制。对View事件分发源码阅读后,总结出此图:

Android View 事件分发.jpg

了解了View的事件分发原理,当然就要知道如何处理事件分发过程中存在的冲突。面对View滑动冲突,首先我们要清楚的知道什么情况下要让那个View响应我们的滑动指令,之后再去通过事件拦截,达到我们想要的结果。作者针对View滑动冲突,给出了两种解决方案。第一种是外部拦截法,即点击事件先经过父容器的拦截方法,如果父容器需要此事件就拦截,不需要此事件就不拦截。父容器onInterceptTouchEvent方法伪代码如下:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            intercepted = false;
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            if (父容器需要当前点击事件) {
                intercepted = true;
            } else {
                intercepted = false;
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            intercepted = false;
            break;
        }
        default:
            break;
    }
    mLastXIntercept = x;
    mLastYIntercept = y;
    return intercepted;
}

第二种方法是内部拦截法,指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器去处理。首先需要重写子元素的dispatchTouchEvent方法,在该方法中调用父容器的requestDisallowInterceptTouchEvent方法处理拦截,伪代码如下:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            parent.requestDisallowInterceptTouchEvent(true);
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            int deltaX = x - mLastX;
            int deltaY = y - mLastY;
            if (父容器需要此类点击事件)){
                parent.requestDisallowInterceptTouchEvent(false);
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            break;
        }
        default:
            break;
    }
    mLastX = x;
    mLastY = y;
    return super.dispatchTouchEvent(event);
}

父容器的onInterceptTouchEvent方法同样需要重写,伪代码如下:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN) {
        return false;
    } else {
        return true;
    }
}

相关文章

网友评论

      本文标题:第3章 View 的事件体系

      本文链接:https://www.haomeiwen.com/subject/rkdbactx.html