Android事件分发02——Activity的dispatchTouchEvent验证一把

本文通过实例验证了Android中Activity的dispatchTouchEvent事件分发过程,并探究了Window中的isOutOfBounds方法的作用,展示了如何判断触屏事件是否超出有效区域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android事件分发02——Activity的dispatchTouchEvent验证一把

通过前面文章 的介绍,我们是不是应该需要一个去验证一下呢?

那么我们开干吧! 走你~~~ GO!

一、Activity的dispatchTouchEventv的分发,来个小例子验证一把

我们简单的来看个小例子验证一下
首先创建一个布局(这个布局最终会是mDecorView的一个子view)

/**
 * @author: qiwenming
 * @date: 17/4/2 下午10:31
 * @className: TestRelativeLayout
 * @description: Activity的dispatchTouchEvent测试
 */
public class TestRelativeLayout extends RelativeLayout {
    private static final String TAG = "TestRelativeLayout";
    public TestRelativeLayout(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i(TAG, "dispatchTouchEvent: "+MotionEvent.actionToString(ev.getAction()));
        return super.dispatchTouchEvent(ev);
    }
}

写一个布局

<?xml version="1.0" encoding="utf-8"?>
<com.qwm.eventdemo.activitydispatch.TestRelativeLayout 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:background="@android:color/holo_orange_light"
    tools:context=".activitydispatch.ActivityDispatchActivity">
</com.qwm.eventdemo.activitydispatch.TestRelativeLayout>

创建一个activity加载这个布局

/**
 * @author: qiwenming
 * @date: 17/4/2 下午10:55
 * @className: ActivityDispatchActivity
 * @description: activity的dispatchTouchEvent测试
 */
public class ActivityDispatchActivity extends BaseActivity {

    private static final String TAG = "ActivityDispatchActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activity_dispatch);
    }

    @Override
    public void onUserInteraction() {
        Log.i(TAG, "onUserInteraction: ");
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i(TAG, "dispatchTouchEvent: "+MotionEvent.actionToString(ev.getAction()));
        return super.dispatchTouchEvent(ev);
    }

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

结果如下图所示:
这里写图片描述

我们点击我们的内容区域的时候如下:

ActivityDispatch: dispatchTouchEvent: ACTION_DOWN
TestRelativeLayout: dispatchTouchEvent: ACTION_DOWN
ActivityDispatch: onTouchEvent:ACTION_DOWN

ActivityDispatch: dispatchTouchEvent: ACTION_UP
ActivityDispatch: onTouchEvent:ACTION_UP

这里面是有两个动作的,按下与抬起。
根据结果我们就验证了上面的结论:
1. 事件首先分发到Activity的dispatchTouchEvent中
2. 接着道ViewGrop的dispatchTouchEvent中
3. 如果ViewGrop没有消费事件,那么事件传递到Activity的OnTouchEvent中

发现的问题:不是说了触摸屏幕以后,事件会传递到Activity的dispatchTouchEvent中来的吗?,那么为什么我们点击状态栏和导航栏没有分发到Activity上来呢?? 我也在找这个答案,解决了在做介绍。

源码下载


二、Window中的isOutOfBounds()验证

由前面的文章我们可知,Activity的 onTouchEvent() 会调用 Window的shouldCloseOnTouch() ,而这个方法里面,会进行四个判断,其他的都很简单,我们来验证其中的 isOutOfBounds()
入了保证我们能够验证简便,我们的 Activity 使用 Dialog 样式。由于isOutOfBounds是Window的私有方法,我们是访问不到的,所有我们把这这个方法 copy 到Activiy中,进行细微个更改,如下

private boolean isOutOfBounds(Context context, MotionEvent event) {
    final int x = (int) event.getX();
    final int y = (int) event.getY();
    final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
    //下面这句代码;原来是 final View decorView = getDecorView(); 其他地方都不变
    final View decorView = getWindow().getDecorView();
    return (x < -slop) || (y < -slop)
            || (x > (decorView.getWidth()+slop))
            || (y > (decorView.getHeight()+slop));
}

为了我们点击屏幕就能看到看到这个方法的结果,我们把这个方法放到 dispatchTouchEvent中,具体代码如下:

/**
 * @author: qiwenming
 * @date: 17/4/4 上午12:33
 * @className: ADisDialogActivity
 * @description: 测试 onTouchEvent方法,其实我们主要来看 window的 isOutOfBounds()方法
 */
public class ADisDialogActivity extends BaseActivity {

    private static final String TAG = "ADisDialogActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_adis_dialog);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(ev.getAction()==MotionEvent.ACTION_DOWN){
            isOutOfBounds(this,ev);
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }


    private boolean isOutOfBounds(Context context, MotionEvent event) {
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
        //下面这句代码;原来是 final View decorView = getDecorView(); 其他地方都不变
        final View decorView = getWindow().getDecorView();
        print(x,y,slop,decorView);
        return (x < -slop) || (y < -slop)
                || (x > (decorView.getWidth()+slop))
                || (y > (decorView.getHeight()+slop));
    }

    private void print(int x,int y,int slop,View decorView){
        Log.i(TAG, "=================================");
        Log.i(TAG, "x: "+x);
        Log.i(TAG, "y: "+y);
        Log.i(TAG, "slop: "+slop);
        Log.i(TAG, "decorView.getWidth(): "+decorView.getWidth());
        Log.i(TAG, "decorView.getHeight(): "+decorView.getHeight());
        Log.i(TAG, "decorView.getWidth()+slop: "+(decorView.getWidth()+slop));
        Log.i(TAG, "decorView.getHeight()+slop: "+(decorView.getHeight()+slop));
        Log.i(TAG, "x < -slop: "+ (x < -slop) );
        Log.i(TAG, "y < -slop: "+(y < -slop));
        Log.i(TAG, "x > (decorView.getWidth()+slop): "+(x > (decorView.getWidth()+slop)));
        Log.i(TAG, "y > (decorView.getHeight()+slop): "+(y > (decorView.getHeight()+slop)));
        boolean isOut =  (x < -slop) || (y < -slop)
                || (x > (decorView.getWidth()+slop))
                || (y > (decorView.getHeight()+slop));
        Log.i(TAG, "isOut: "+isOut);
    }
}

结果图示

这里写图片描述

文字结果

 =================================
 x: 290
 y: 94
 slop: 32
 decorView.getWidth(): 512
 decorView.getHeight(): 186
 decorView.getWidth()+slop: 544
 decorView.getHeight()+slop: 218
 x < -slop: false
 y < -slop: false
 x > (decorView.getWidth()+slop): false
 y > (decorView.getHeight()+slop): false
 isOut: false
 =================================
 x: -13
 y: -4
 slop: 32
 decorView.getWidth(): 512
 decorView.getHeight(): 186
 decorView.getWidth()+slop: 544
 decorView.getHeight()+slop: 218
 x < -slop: false
 y < -slop: false
 x > (decorView.getWidth()+slop): false
 y > (decorView.getHeight()+slop): false
 isOut: false
 =================================
 x: 533
 y: 190
 slop: 32
 decorView.getWidth(): 512
 decorView.getHeight(): 186
 decorView.getWidth()+slop: 544
 decorView.getHeight()+slop: 218
 x < -slop: false
 y < -slop: false
 x > (decorView.getWidth()+slop): false
 y > (decorView.getHeight()+slop): false
 isOut: false
 =================================
 x: 464
 y: 430
 slop: 32
 decorView.getWidth(): 512
 decorView.getHeight(): 186
 decorView.getWidth()+slop: 544
 decorView.getHeight()+slop: 218
 x < -slop: false
 y < -slop: false
 x > (decorView.getWidth()+slop): false
 y > (decorView.getHeight()+slop): true
 isOut: true

到此,我们就验证了,我们前面说的,是否超出边界有一个范围值 16dp。

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值