浅谈Android 事件分发机制(一)

Android事件分发机制是Android开发者必须了解的知识,这方面的内容很多,自己纯看文章总觉得比较抽象,自己写了个demo,理一下事件分发的流程,加深印象。

view结构


PhoneWindow 的指示通过 DecorView 传递给下面的 View,下面 View 的信息也通过 DecorView 回传给 PhoneWindow。这里我们主要聊聊ViewGroup与view的事件分发


注‘Android技术交流群878873098,欢迎大家加入交流,畅谈!本群有免费学习资料视频且免费分享

事件分发dispatchTouchEvent一般改写不多,主要关注另外两个。
事件拦截onInterceptTouchEvent,true,拦截,交给自己的onTouchEvent处理,不传给下级;false,不拦截,传给下级。
事件消费onTouchEvent,true,自己搞定消费,不用上传;false,上传。

事件模拟


如图布局,最外层的父布局ViewGroupA,中间层的ViewGroupB,最里层的ViewC

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <com.qhyccd.event.ViewGroupA
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="100dp"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@color/colorRed">

        <com.qhyccd.event.ViewGroupB
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:background="@color/colorYellow">

            <com.qhyccd.event.ViewC
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:background="@color/colorBlue" />

        </com.qhyccd.event.ViewGroupB>

    </com.qhyccd.event.ViewGroupA>

</FrameLayout>

首先模拟下以上场景,A、B、C三个角色,A>B>C

ViewGroupA

public class ViewGroupA extends LinearLayout {
    public ViewGroupA(Context context) {
        super(context);
    }

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

    public ViewGroupA(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupA dispatchTouchEvent  ");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupA onInterceptTouchEvent  ");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewGroupA onTouchEvent  ");
        return super.onTouchEvent(event);
    }
}

ViewGroupB

public class ViewGroupB extends LinearLayout {

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

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

    public ViewGroupB(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupB dispatchTouchEvent  ");
        return super.dispatchTouchEvent(ev);;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("》》》", " ViewGroupB onInterceptTouchEvent  ");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewGroupB onTouchEvent  ");
        return super.onTouchEvent(event);
    }

}

ViewC

public class ViewC extends View {

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

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

    public ViewC(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewC dispatchTouchEvent  ");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("》》》", " ViewC onTouchEvent  ");
        return super.onTouchEvent(event);
    }
}

情景一

默认情况下,点击C区域

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewC dispatchTouchEvent 
ViewC onTouchEvent  
ViewGroupB onTouchEvent  
ViewGroupA onTouchEvent

可见,事件是从A->B->C,再从C->B->A回传

情景二

A想自己把事件拦截,不给下级处理,A里面onInterceptTouchEvent返回ture拦截事件

ViewGroupA dispatchTouchEvent 
ViewGroupA onInterceptTouchEvent
ViewGroupA onTouchEvent

情景三

B想自己把事件拦截,不给下级处理,B里面onInterceptTouchEvent返回ture拦截事件。

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewGroupB onTouchEvent  
ViewGroupA onTouchEvent

B这里只是对事件拦截不往下传递,还是会往上回传的。
如果想让B自己把事件消费,不往上级传递,B的onTouchEvent返回true

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewGroupB onTouchEvent

情景四

C属于最底层view,对事件没有拦截权限,C自己想把事件消费了,C的onTouchEvent返回true,不再往上级回传

ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent  
ViewGroupB onInterceptTouchEvent  
ViewC dispatchTouchEvent 
ViewC onTouchEvent

以上是静态点击事件处理流程,模拟的事件分发机制,通过log打印可以看到事件的传递流程,这篇文章属于基础篇章,后续我们给view添加滑动,通过处理滑动冲突进一步理解事件的分发机制,敬请期待下一篇。

注‘Android技术交流群878873098,欢迎大家加入交流,畅谈!本群有免费学习资料视频且免费分享

下载方式:https://pan.quark.cn/s/a4b39357ea24 布线问题(分支限界算法)是计算机科学和电子工程领域中个广为人知的议题,它主要探讨如何在印刷电路板上定位两个节点间最短的连接路径。 在这议题中,电路板被构建为个包含 n×m 个方格的矩阵,每个方格能够被界定为可通行或不可通行,其核心任务是定位从初始点到最终点的最短路径。 分支限界算法是处理布线问题的种常用策略。 该算法与回溯法有相似之处,但存在差异,分支限界法仅需获取满足约束条件的个最优路径,并按照广度优先或最小成本优先的原则来探索解空间树。 树 T 被构建为子集树或排列树,在探索过程中,每个节点仅被赋予次成为扩展节点的机会,且会次性生成其全部子节点。 针对布线问题的解决,队列式分支限界法可以被采用。 从起始位置 a 出发,将其设定为首个扩展节点,并将与该扩展节点相邻且可通行的方格加入至活跃节点队列中,将这些方格标记为 1,即从起始方格 a 到这些方格的距离为 1。 随后,从活跃节点队列中提取队首节点作为下个扩展节点,并将与当前扩展节点相邻且未标记的方格标记为 2,随后将这些方格存入活跃节点队列。 这过程将持续进行,直至算法探测到目标方格 b 或活跃节点队列为空。 在实现上述算法时,必须定义个类 Position 来表征电路板上方格的位置,其成员 row 和 col 分别指示方格所在的行和列。 在方格位置上,布线能够沿右、下、左、上四个方向展开。 这四个方向的移动分别被记为 0、1、2、3。 下述表格中,offset[i].row 和 offset[i].col(i=0,1,2,3)分别提供了沿这四个方向前进 1 步相对于当前方格的相对位移。 在 Java 编程语言中,可以使用二维数组...
源码来自:https://pan.quark.cn/s/a4b39357ea24 在VC++开发过程中,对话框(CDialog)作为典型的用户界面组件,承担着与用户进行信息交互的重要角色。 在VS2008SP1的开发环境中,常常需要满足为对话框配置个性化背景图片的需求,以此来优化用户的操作体验。 本案例将系统性地阐述在CDialog框架下如何达成这功能。 首先,需要在资源设计工具中构建个新的对话框资源。 具体操作是在Visual Studio平台中,进入资源视图(Resource View)界面,定位到对话框(Dialog)分支,通过右键选择“插入对话框”(Insert Dialog)选项。 完成对话框内控件的布局设计后,对对话框资源进行保存。 随后,将着手进行背景图片的载入工作。 通常有两种主要的技术路径:1. **运用位图控件(CStatic)**:在对话框界面中嵌入个CStatic控件,并将其属性设置为BST_OWNERDRAW,从而具备自主控制绘制过程的权限。 在对话框的类定义中,需要重写OnPaint()函数,负责调用图片资源并借助CDC对象将其渲染到对话框表面。 此外,必须合理处理WM_CTLCOLORSTATIC消息,确保背景图片的展示不会受到其他界面元素的干扰。 ```cppvoid CMyDialog::OnPaint(){ CPaintDC dc(this); // 生成设备上下文对象 CBitmap bitmap; bitmap.LoadBitmap(IDC_BITMAP_BACKGROUND); // 获取背景图片资源 CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap* pOldBitmap = m...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值