Android事件分发机制案例分析(一)

 最近在做东西的时候发现自己对事件的分发(传递)机制理解的并不清楚,可以说是错误的理解了事件分发机制。对此,自己找了一些实例的例子,来加深对Android的时间分发机制的理解。废话不多说,直入主题。
 下图是这个案例的实现界面:
 UI实现效果图
 对于上面实现的xml代码很简单,下图注明其容器和控件的结构:
 这里写图片描述
 如果上面的示意图表达的不清楚,请看以下代码:
 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.test.youkumenu.MainActivity">

    <RelativeLayout
        android:id="@+id/rl_level1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1">

        <ImageButton
            android:id="@+id/ib_home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@null"
            android:src="@drawable/icon_home" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_level2"
        android:layout_width="180dp"
        android:layout_height="90dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2">

        <ImageButton
            android:id="@+id/ib_menu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:background="@null"
            android:src="@drawable/icon_menu" />

        <ImageButton
            android:id="@+id/search"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="5dp"
            android:background="@android:color/transparent"
            android:src="@drawable/icon_search" />
        <ImageButton
            android:id="@+id/question"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="5dp"
        android:background="@android:color/transparent"
            android:src="@drawable/icon_myyouku" />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_level3"
        android:layout_width="280dp"
        android:layout_height="140dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3">
        <ImageButton
            android:id="@+id/house"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:background="@null"
            android:src="@drawable/channel4" />
        <ImageButton
            android:id="@+id/music"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentStart="true"
            android:layout_marginBottom="11dp"
            android:layout_marginStart="14dp"
            android:background="@null"
            android:src="@drawable/channel1" />
        <ImageButton
            android:id="@+id/microphone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_alignTop="@+id/music"
            android:layout_marginEnd="12dp"
            android:background="@null"
            android:src="@drawable/channel7" />
        <ImageButton
            android:id="@+id/media"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/tv_show"
            android:layout_toEndOf="@+id/music"
            android:background="@null"
            android:src="@drawable/channel2" />

        <ImageButton
            android:id="@+id/tv_show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@+id/microphone"
            android:layout_marginBottom="14dp"
            android:layout_toStartOf="@+id/microphone"
            android:background="@null"
            android:src="@drawable/channel5" />

        <ImageButton
            android:id="@+id/editing"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/monkey"
            android:layout_marginEnd="15dp"
            android:layout_toStartOf="@+id/tv_show"
            android:background="@null"
            android:src="@drawable/channel6" />

        <ImageButton
            android:id="@+id/monkey"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/house"
            android:layout_marginStart="11dp"
            android:layout_toEndOf="@+id/media"
            android:background="@null"
            android:src="@drawable/channel3" />
    </RelativeLayout>
</RelativeLayout>

 上面的布局结构是为了实现优酷菜单的动画效果,但是本次不是针对动画,所以就不做实现的说明了。
 对上图而言,结构上level2部分覆盖了level1,level3部分覆盖了level2,对于level3而言没有谁覆盖它,所以它的事件传递序列很简单,
 即:根布局容器RelativeLayout—>level3的RelativeLayout容器—>level3上上面的原子View(不能拆分的控件,最基本结构的控件)
 那么,如果要设置level2和level1容器(RelativeLayout)
的子控件的点击事件,怎么办呢?
 直接添加View.OnClickListener接口,使用setOnClickListener设置监听?
 运行结果就不截图了,每次的点击事件都直接被level3容器视图消费了,只有level3的OnClick事件打印出了log,为什么呢?那就要分析下Android事件分发机制的原理了。借助本次的实例,做以下分析,如图:
 这里写图片描述
 相信看了上面这张图,应该很容易理解为什么点击事件会被level3拦截,而不继续向下层传递了,对于每一个level,其内部的事件传递跟上面一样,只是原子控件没有onInterceptTouchEvent方法,因为他是最基本的控件,所以上面让level1,level2响应level3传递下来的事件就很容易解决了.
 想让level2及其控件响应事件,就让level3的onTouch返回false,不消费事件,让其向level2传递,一次类推,让level1及其控件响应事件,则然level2的onTouch返回false,不消费事件即可,下面看实际代码。
 

private void initView() {
        //事件拦截处理
        //rl_level3需要把事件传递给rl_level2和rl_level1
        rl_level1 = (RelativeLayout) findViewById(R.id.rl_level1);
        rl_level1.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
        /*
        rl_level1.onInterceptTouchEvent(MotionEvent ev); 拦截TouchEvent
        rl_level1.dispatchTouchEvent(); 分发TouchEvent
        rl_level1.onTouchEvent() 触摸事件
        */
        rl_level2 = (RelativeLayout) findViewById(R.id.rl_level2);
        rl_level2.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
        rl_level3 = (RelativeLayout) findViewById(R.id.rl_level3);
        //让上层的RelativeLayout不消费
        rl_level3.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
        ib_home = (ImageButton) findViewById(R.id.ib_home);
        ib_home.setOnClickListener(this);
        ib_menu = (ImageButton) findViewById(R.id.ib_menu);
        ib_menu.setOnClickListener(this);
        findViewById(R.id.search).setOnClickListener(this);//搜索
        findViewById(R.id.question).setOnClickListener(this);//问题
        findViewById(R.id.media).setOnClickListener(this);//多媒体
        findViewById(R.id.editing).setOnClickListener(this);//剪辑
        findViewById(R.id.house).setOnClickListener(this);//
        findViewById(R.id.microphone).setOnClickListener(this);
        findViewById(R.id.music).setOnClickListener(this);
        findViewById(R.id.monkey).setOnClickListener(this);
        findViewById(R.id.tv_show).setOnClickListener(this);
    }

 运行结果:
 这里写图片描述
 可以看出,所有的图标按钮都响应了对应的事件。

猜你喜欢

转载自blog.csdn.net/yyg_2015/article/details/54635907
今日推荐