• Anroid事件分发


       因为最近因个人原因离职,面试的时候,有人问到了Android中事件分发机制的过程,因为忘得差不多了,没答好,所以回来后,想写了个Demo,重新复习一遍。

       一般来说,Android的组件其实可以分为两类,即View和ViewGroup,而ViewGroup又继承于View。对于ViewGroup的是事件分发主要涉及到三个方法:

      dispatchTouchEvent(MotionEvent ev),onInterceptTouchEvent(MotionEvent ev)和onTouchEvent(MotionEvent event),而View主要涉及到

      dispatchTouchEvent(MotionEvent ev)和onTouchEvent(MotionEvent event)。顾名思义,dispatchTouchEvent用于分发Touch事件,

      onInterceptTouchEvent用于拦截Touch事件,而onTouchEvent则是用于处理Touc事件。

     

       首先,我们写一个简单的Demo来看看,

    public class MyLinearLayout extends LinearLayout {
    
        public MyLinearLayout(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public MyLinearLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyLinearLayout(Context context) {
            super(context);
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.d("test", "MyLinearLayout"+" dispatchTouchEvent");
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.d("test", "MyLinearLayout"+" onInterceptTouchEvent");
            return super.onInterceptTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.d("test", "MyLinearLayout"+" onTouchEvent");
            return super.onTouchEvent(event);
        }
        
    }
    public class MyView extends TextView {
    
        public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public MyView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyView(Context context) {
            super(context);
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            Log.d("test", "MyView"+" dispatchTouchEvent");
            return super.dispatchTouchEvent(event);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.d("test", "MyView"+" onTouchEvent");
            return super.onTouchEvent(event);
        }
    
    }
    <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"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.example.eventdemo.MainActivity" >
    
        <com.example.test1.MyLinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >
            <com.example.test1.MyView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="00000000000000000000"
                />
            
        </com.example.test1.MyLinearLayout>
    
    </RelativeLayout>

    上面我主要定义了一个ViewGroup(MyLinearLayout)和一个View(MyView),然后分别打印出dispatchTouchEvent(MotionEvent ev),onInterceptTouchEvent(MotionEvent ev)和onTouchEvent(MotionEvent event)的Log:

     通过上面的Log可以看出,ViewGroup和View中的事件默认分发顺序是:ViewGruop.dispatchTouchEvent --> ViewGruop.onInterceptTouchEvent

     --> View.dispatchTouchEvent --> View.onTouchEvent --> ViewGroup.onTouchEvent.

     那如果我们对View的onTouchEvent事件的返回值修改下,会变成什么样呢?

     首先,我将MyView中的onTouchEvent方法中直接return true,然后看下Log:

     

     可以发现,MyLinearLayout的onTouchEvent没有执行,这是因为这次Touch事件已经被MyView消费了,即如果我们在方法中直接return true,那么事件就不会继续分发下去了。

     接着,我们在MyLinearLayout的dispatchTouchEvent方法中return true,然后看Log:

     总结如下:

    • dispatchTouchEvent返回true,意味后续不会将事件进行分发,而是直接在dispatchTouchEvent中进行拦截,即后续的ACTION_MOVE,ACTION_UP,ACTION_CANCEL事件只会触发ViewGroup和ViewGroup之前路径的View以及ViewGroup(需要注意的是,如果是在onTouch中,返回true,则下次的ACTION_DOWN,ACTION_UP就只会触发该ViewGroup的onTouch事件,即系统是会记住消费了onTouch事件的那个ViewGroup来传递事件)的dispatchTouchEvent和onInterceptTouchEvent
      ,而不会触发ViewGroup以及ViewGroup之后的View的onInterceptTouchEvent()和onTouchEvent()事件.
    • dispatchTouchEvent返回返回false,意味着不处理该事件,也不往下分发事件。即后续不会收到ACTION_MOVE,ACTION_UP,ACTION_CANCEL事件.
    • 返回super.dispatchTouchEvent(ev)意味着不处理该事件,而是依次向子View分发该事件,直到找到需要消费本次事件的View.

      所以如果我们需要将事件拦截下来的话,直接return true就可以了。

  • 相关阅读:
    关于头文件
    函数重载和函数模板
    引用和内联函数
    OpenCV中图像处理
    MFC中关于子进程创建和关闭操作
    MFC中的CListControl控件
    MFC中Picture控件显示图像
    MFC CString 和int相互转化
    MFC下拉框
    MFC中关于CListBox控件添加水平滚动条
  • 原文地址:https://www.cnblogs.com/xiaoyang2009/p/5017821.html
Copyright © 2020-2023  润新知