Android事件分发 分析

Android事件分发 分析

什么是事件的 分发

  • 用户通过屏幕与手机交互的时候,每一次点击、长按、移动等都是一个事件。

  • 事件分发机制:某一个事件从屏幕传递各个View,由View来使用这一事件(消费是事件)或者忽略这一事件(不消费事件),这整个过程的控制。

事件分发的对象是谁

  • 系统把事件封装为MotionEvent对象,事件分发的过程就是MotionEvent分发的过程。

事件类型

  • 按下(ACTION _DOWN)

  • 移动 (ACTION_MOVE)

  • 抬起 (ACTION_UP)

  • 取消 (ACTION_CANUCEL)

事件序列

  • 从手指按下屏幕开始,到手指离开屏幕所产生的一系列事件。

传递层级

  • Activity ->Window ->DecorView -> ViewGroup ->View

主要传递对象及顺序

  • Activity 、 ViewGroup、 View

Activity中

  • dispatchTouchEvent(MotionEvent ev)

  • onTouchEvent(MotionEvent event)

在这里插入图片描述

ViewGroup中

  • dispatchTouchEvent(MotionEvent ev)

  • onInterceptTouchEvent(MotionEvent ev)

  • onTouchEvent(MotionEvent event)

在这里插入图片描述

View中

  • dispatchTouchEvent(MotionEvent ev)

  • onTouchEvent(MotionEvent event)

在这里插入图片描述

验证 (事件传递流程)

代码测试

MainActivity


public class MainActivity extends AppCompatActivity {
    /**
     * ViewsGroup:dispatchTouchEvent
     * 1.去判断是否需要拦截事件
     * 2.在当前ViewGroup中找到用户真正点击的View
     * 3.分发事件到View上
     * @param savedInstanceState
     */
     public static  final  String TAG="测试";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"MainActivity:dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MainActivity:onTouchEvent");
        return super.onTouchEvent(event);
    }
}

MyViewGroup

public class MyViewGroup extends FrameLayout {
    public MyViewGroup(@NonNull Context context) {
        super(context);
    }

    public MyViewGroup(@NonNull Context context, @NonNull AttributeSet attrs) {
        super(context, attrs);
    }

    public MyViewGroup(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyViewGroup(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"MyViewGroup:dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e(TAG,"MyViewGroup : onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyViewGroup:onTouchEvent");
        return super.onTouchEvent(event);
    }

}

MyView

public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

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

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyView:dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyView:onTouchEvent");
        return super.onTouchEvent(event);

    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<com.example.a13262.myapplication.MyViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#ff0000">

    <com.example.a13262.myapplication.MyView
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:background="#000"
       />

</com.example.a13262.myapplication.MyViewGroup>

运行

在这里插入图片描述

默认传递流程

  • MainActivity:dispatchTouchEvent —> MyViewGroup:dispatchTouchEvent —>MyViewGroup : onInterceptTouchEvent—> MyView:dispatchTouchEvent —>MyView:onTouchEvent —> MyViewGroup:onTouchEvent —>MainActivity:onTouchEvent
同一个事件序列,如果子View(ViewGroup) 没有处理事件(没有消费事件),那么后续事件就不会再传递到子View中。
  • MainActivity:dispatchTouchEvent —>MainActivity:onTouchEven

验证 (cancel事件)

代码测试

MainActivity

public class MainActivity extends AppCompatActivity {
    /**
     * ViewsGroup:dispatchTouchEvent
     * 1.去判断是否需要拦截事件
     * 2.在当前ViewGroup中找到用户真正点击的View
     * 3.分发事件到View上
     * @param savedInstanceState
     */
     public static  final  String TAG="测试";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"MainActivity:dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MainActivity:onTouchEvent");
        return super.onTouchEvent(event);
    }
}

MyScrollView

public class MyScrollView extends ScrollView {
    public MyScrollView(Context context) {
        super(context);
    }

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

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean b = super.onInterceptTouchEvent(ev);
        Log.e(TAG,"MyScrollView:onInterceptTouchEvent---------------"+b);
        return  b;
    }

}

MyButton

public class MyButton extends AppCompatButton {

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

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

    public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyButton:onTouchEvent---------------"+event.getAction());
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyButton:dispatchTouchEvent---------------"+event.getAction());
        return super.dispatchTouchEvent(event);
    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
1<com.example.a13262.myapplication.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#fc0000">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <com.example.a13262.myapplication.MyButton
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:text="测试取消事件"
            />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="5000dp" />
    </LinearLayout>

</com.example.a13262.myapplication.MyScrollView>

运行

在这里插入图片描述

验证( ViewGroup事件拦截)

代码测试

MainActivity

public class MainActivity extends AppCompatActivity {
    /**
     * ViewsGroup:dispatchTouchEvent
     * 1.去判断是否需要拦截事件
     * 2.在当前ViewGroup中找到用户真正点击的View
     * 3.分发事件到View上
     * @param savedInstanceState
     */
     public static  final  String TAG="测试";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"MainActivity:dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MainActivity:onTouchEvent");
        return super.onTouchEvent(event);
    }
}

MyViewGroup

public class MyViewGroup extends FrameLayout {
    public MyViewGroup(@NonNull Context context) {
        super(context);
    }

    public MyViewGroup(@NonNull Context context, @NonNull AttributeSet attrs) {
        super(context, attrs);
    }

    public MyViewGroup(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyViewGroup(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"MyViewGroup:dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e(TAG,"MyViewGroup : onInterceptTouchEvent");
        //返回 true 标志事件被拦截不会传递到MyView中去了
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyViewGroup:onTouchEvent");
        Log.e(TAG,"MyViewGroup:正在处理事件");
        return  true;
    }

}

MyView

public class MyView extends View {
    public MyView(Context context) {
        super(context);
    }

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

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyView:dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"MyView:onTouchEvent");
        return super.onTouchEvent(event);

    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<com.example.a13262.myapplication.MyViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#ff0000">

    <com.example.a13262.myapplication.MyView
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:background="#000"
       />

</com.example.a13262.myapplication.MyViewGroup>

运行

在这里插入图片描述

可以看出事件没有进入MyView中

到此,事件分发简单的流程就梳理完了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值