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。