最近总结了一下Android事件分发机制。由于场景比较多,现先从最简单的场景开始讲解。一个FrameLayout嵌套一个LinearLayout,LinearLayout中嵌套一个View。我们接下来就来分析一下这个最经典,也是最简单的事件传递场景中,事件是如何传递的。
首先为了方便观察,先自定义一个MyFrameLayout,重写三个方法并添加日志:
[AppleScript] 纯文本查看 复制代码 package com.itheima.touchdemo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
public class MyFrameLayout extends FrameLayout {
public MyFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyFrameLayout(Context context) {
super(context);
}
// 事件处理
@Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("FrameLayout---->onTouchEvent---start");
boolean b = super.onTouchEvent(event);
System.out.println("FrameLayout---->onTouchEvent---end---" + b);
return b;
}
// 事件拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
System.out.println("FrameLayout---->onInterceptTouchEvent---start");
boolean b = super.onInterceptTouchEvent(ev);
System.out.println("FrameLayout---->onInterceptTouchEvent---end---" +b);
return b;
}
// 事件分发
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
System.out.println(ev.getX() + "----- " + ev.getY());
System.out.println("FrameLayout---->dispatchTouchEvent---start");
boolean b = super.dispatchTouchEvent(ev);
System.out.println("FrameLayout---->dispatchTouchEvent---end--->" + b);
return b;
}
}
同理自定义MyLinearLayout,并重写三个方法便于观察你:
[AppleScript] 纯文本查看 复制代码 package com.itheima.touchdemo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyLinearLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
// 事件处理
@Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("LinearLayout---->onTouchEvent---start");
boolean b = super.onTouchEvent(event);
System.out.println("LinearLayout---->onTouchEvent---end---" + b);
return b;
}
// 事件拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
System.out.println("LinearLayout---->onInterceptTouchEvent---start");
boolean b = super.onInterceptTouchEvent(ev);
System.out.println("LinearLayout---->onInterceptTouchEvent---end---" +b);
return b;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
System.out.println("LinearLayout---->dispatchTouchEvent---start");
boolean b = super.dispatchTouchEvent(ev);
System.out.println("LinearLayout---->dispatchTouchEvent---end--->" + b);
return b;
}
}
自定义MyView,重写dispatchTouchEvent,onTouchEvent两个方法,并添加日志便于观察:
[AppleScript] 纯文本查看 复制代码 package com.itheima.touchdemo;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MyView extends View {
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
// 事件处理
@Override
public boolean onTouchEvent(MotionEvent event) {
System.out.println("View---->onTouchEvent---start");
boolean b = super.onTouchEvent(event);
System.out.println("View---->onTouchEvent---end---" + b);
return b;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
System.out.println("View---->dispatchTouchEvent---start");
boolean b = super.dispatchTouchEvent(ev);
System.out.println("View---->dispatchTouchEvent---end--->" + b);
return b;
}
}
Activity中初始化view时,动态将三个View依次嵌套起来:
[AppleScript] 纯文本查看 复制代码 package com.itheima.touchdemo;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = init_view();
setContentView(view);
}
private View init_view() {
MyFrameLayout myFrameLayout = new MyFrameLayout(this);
myFrameLayout.setBackgroundColor(Color.RED);
MyLinearLayout myLinearLayout = new MyLinearLayout(this);
myLinearLayout.setBackgroundColor(Color.GREEN);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(200, 200);
params.gravity = Gravity.CENTER;
myFrameLayout.addView(myLinearLayout, params);
MyView myView = new MyView(this);
myView.setBackgroundColor(Color.GRAY);
LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(100, 100);
params1.gravity = Gravity.CENTER_VERTICAL;
myLinearLayout.setGravity(Gravity.CENTER);
myLinearLayout.addView(myView,params1);
// FrameLayout.LayoutParams params2 = new FrameLayout.LayoutParams(100,
// 100);
// params2.gravity = Gravity.CENTER;
// myFrameLayout.setGravity(Gravity.CENTER);
// myFrameLayout.addView(myView, params2);
return myFrameLayout;
}
}
红色的是MyFrameLayout,绿色的是MyLInearLayout,灰色的是MyView。现在我将手指按在灰色的区域按下时,事件的传递过程是这样的:
[AppleScript] 纯文本查看 复制代码 03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->dispatchTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onInterceptTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onInterceptTouchEvent---end---false
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->dispatchTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onInterceptTouchEvent---start
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onInterceptTouchEvent---end---false
03-31 14:40:41.581 2465-2465/com.itheima.touchdemo I/System.out: View---->dispatchTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: View---->onTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: View---->onTouchEvent---end---false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: View---->dispatchTouchEvent---end--->false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->onTouchEvent---end---false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: LinearLayout---->dispatchTouchEvent---end--->false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onTouchEvent---start
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->onTouchEvent---end---false
03-31 14:40:41.582 2465-2465/com.itheima.touchdemo I/System.out: FrameLayout---->dispatchTouchEvent---end--->false
从这个日志中不难看出,事件的传递流程是这样的。先从最外层的MyFrameLayout的dispatchTouchEvent开始,然后问自己的onInterceptTouchEvent是否拦截,不拦截然后将事件传递给MyLinearLayout的dispatchTouchEvent,然后调用MyLinearLayout的onInterceptTouchEvent是否拦截,不拦截,将事件传递给MyView的dispatchTouchEvent,因为Myview是最后一层,所以要调用onTouchEvent,看是否处理,如果不处理,再讲事件向上传递到MyLinearLayout的onTouchEvent,如果MyLinearLayout也不处理,事件接着向上传递到MyFrameLayout的onTouchEvent。如果MyFrameLayout也不处理,那么这个事件就会丢失,接下来的move事件up事件都不会再往下传递。
我们已经分析完了最简单,也是最经典的事件传递过程。这一篇就到这里。接下来我们下一篇再来一块分析一下如果MyFrameLayout,MyLinearLayout,MyView中有人处理这个事件。或者有人拦截这个事件,事件的传递过程又会怎样呢?敬请关注Android事件分发机制(二)。
|