Android事件分发

在android 界一直流传着一句话,谁能掌握view,谁就能掌握android(这是我自己装比说的)

不过view 这一块在android中 确实是 由普通android 向高级android 进发的必须要走的一步路,我准备 一边学,一边记录自己  学习view 的历程,今天 先来讲讲 view 的事件分发机制--

先看一张图:

 

这张图大家应该都很熟悉, 所谓的事件分发机制 无非就是 view的 相关触摸事件的传递过程,

比如我点击一下屏幕,图中各view 的 触摸事件分别是如何 响应的,分别有哪些事件会得到响应,

废话不多话,代码撸起来:

 

Viewgroup:A

public class OneView extends LinearLayout {


    public OneView(Context context) {
        super(context);
    }

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



    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("TEST", "OneView dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("TEST", "OneView onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TEST", "OneView onTouchEvent");
        return super.onTouchEvent(event);
    }
}

 

Viewgroup:B

public class TwoView extends LinearLayout {


    public TwoView(Context context) {
        super(context);
    }

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



    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("TEST", "TwoView dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("TEST", "TwoView onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TEST", "TwoView onTouchEvent");
        return super.onTouchEvent(event);
    }
}

 

View:C

public class ThreeView extends View {

    private Paint paint;
    private int Withs;
    private int Hiths;

    public ThreeView(Context context) {
        super(context);
    }

    public ThreeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        Withs = w / 2;
        Hiths = h / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint = new Paint();

        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充
        paint.setStrokeWidth(10f);         //设置画笔宽度为10px
        paint.setTextSize(30);
        canvas.drawText("我是帅比", Withs, Hiths, paint);

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("TEST", "ThreeView dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TEST", "ThreeView onTouchEvent");
        return super.onTouchEvent(event);
    }
}

 

 

 

当我点金 C 的时候,事件的调用log分别为:

很清楚 ,调用流程依次为: 最外层view A:dispatchTouchEvent---> onInterceptTouchEvent  ---->..........

如果这个点击事件从最外层到最里层都没有被 拦截消费(即return true),则会继续从最底层的view 的 onTouchEvent 事件 往上层的 onTouchEvent 事件传递,直到被消费,如果 上层也没有消费,则此次点击事件就被流放,说到这里,其实 这并不是 所有的布局,在我们 肉眼到的布局之外,还包着有另外的布局,比如 标题栏什么的,那么这些view 在哪里:

如下图:

Rootview 相当于我们布局的根布局 LinearLayout,在其之上 的View结构中莫名多出来的两个东西,PhoneWindow 和 DecorView ,这两个我们并没有在Layout文件中定义过,但是为什么会存在呢?

仔细观察上面的 layout 文件,你会发现一个问题,我在 layout 文件中的最顶层 View(Group) 的大小并不是填满父窗体的,留下了大量的空白区域,由于我们的手机屏幕不能透明,所以这些空白区域肯定要显示一些东西,那么应该显示什么呢?

有过安卓开发经验的都知道,屏幕上没有View遮挡的部分会显示主题的颜色。不仅如此,最上面的一个标题栏也没有在 layout 文件中,这个标题栏又是显示在哪里的呢?

你没有猜错,这个主题颜色和标题栏等内容就是显示在DecorView中的。

现在知道 DecorView 是干什么的了,那么PhoneWindow 又有什么作用?

要了解 PhoneWindow 是干啥的,首先要了解啥是 Window ,看官方说明:

Abstract base class for a top-level window look and behavior policy. An instance of this class should be used as the top-level view added to the window manager. It provides standard UI policies such as a background, title area, default key processing, etc.

简单来说,Window是一个抽象类,是所有视图的最顶层容器,视图的外观和行为都归他管,不论是背景显示,标题栏还是事件处理都是他管理的范畴,它其实就像是View界的太上皇(虽然能管的事情看似很多,但是没实权,因为抽象类不能直接使用)。

而 PhoneWindow 作为 Window 的唯一亲儿子(唯一实现类),自然就是 View 界的皇帝了,PhoneWindow 的权利可是非常大大,不过对于我们来说用处并不大,因为皇帝平时都是躲在深宫里面的,虽然偶尔用特殊方法能见上一面,但想要完全指挥 PhoneWindow 为你工作是很困难的。

而上面说的 DecorView 是 PhoneWindow 的一个内部类,其职位相当于小太监,就是跟在 PhoneWindow 身边专业为 PhoneWindow 服务的,除了自己要干活之外,也负责消息的传递,PhoneWindow 的指示通过 DecorView 传递给下面的 View,而下面 View 的信息也通过 DecorView 回传给 PhoneWindow。

这些额外的就就到这里,有兴趣的可以自行谷歌,我们继续 我们的事件分发机制,

如最上面在没有任何拦截的时候,事件分发可谓是一马平川,那么如果我们想搞点事情呢,

比如,我在B中拦截掉这个点击事件,我们看看 事件是如何分发的,

如图我在 onInterceptTouchEvent 中直接拦截了点击事件,那么现在的传递是怎么样呢? 

如下:

 

果然 事件没有继续往下传递到C,直接触发了 B view 的onTouchEvent,由于 B中的 onTouchEvent 也没有消费此次点击事件,故会继续往上层的 onTouchEvent 事件传递,

如果我们 在B 的onTouchEvent 中 消费了此次事件呢,又会如何呢,

我们把 如图:

onTouchEvent 的返回改为true,表示消费此次点击事件,结果调用方法如下:

 

 

onTouchEvent 走了三次,为什么会走三次,因为 

onTouchEvent有3个回掉,分别为 

MotionEvent.ACTION_DOWN:

MotionEvent.ACTION_MOVE:

MotionEvent.ACTION_UP:

按下,移动,抬手,

讲到这里,我想大家基本明白事件的分发机制是如何的了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值