您的位置:首页 > 移动开发 > Android开发

android事件分发机制总结

2014-10-09 09:45 323 查看
摘要: 再看了大神的博客后,开始总结一下android的时间分发。

Android事件分发机制

在android 普通view(不包含ViewGroup)和activity中主要有一下两个方法处理事件:

public boolean dispatchTouchEvent(MotionEvent ev) // 分发事件
public boolean onTouchEvent(MotionEvent event)     // 处理事件


在ViewGroup中还多一个方法:

public boolean onInterceptTouchEvent(MotionEvent ev) // 拦截事件


1、在activity中,顺序是:事件分发->事件处理,如果在事件分发时消费了某个事件(return true)则事件处理将不会接收到该事件。

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 事件分发
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_MOVE) {
System.out.println("dispatchTouchEvent-->ACTION_MOVE");
return true; // 表示我消费了,不继续分发
}
return super.dispatchTouchEvent(ev);
}
// 处理事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("onTouchEvent-->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("onTouchEvent-->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("onTouchEvent-->ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
}


以上代码的结果:

onTouchEvent-->ACTION_DOWN

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

dispatchTouchEvent-->ACTION_MOVE

onTouchEvent-->ACTION_UP

从结果上看:ACTION_MOVE并没有到onTouchEvent中,因为我们在dispatchTouchEvent判断,如果是ACTION_MOVE则return true表示消耗掉该事件,事件就不会分发到onTouchEvent中,所有onTouchEvent只能接收到ACTION_DOWN和ACTION_UP事件。

2、普通view的事件分发

一个普通view的事件由dispatchTouchEvent分发事件,事件的顺序是ACTION_DOWN、ACTION_MOVE、ACTION_UP,如果有一个事件被消费掉,其他的事件不会执行到;分发事件由onTouch首先接收到,如果onTouch返回true了,表示消费掉了该事件,那么该view的click事件将不会执行。

mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("onTouch..."+event.getAction());
return true;  // 消费了该事件,下面的click事件不会执行
}
});
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 因为上面的onTouch把事件消费了,则这里执行不到
System.out.println("onClick...");
}
});


3、ViewGroup的事件分发:

ViewGroup的事件分发稍微麻烦点,以自定义的LinearLayout : MyLayout为例;

事件发生,首先由MyLayout的dispatchTouchEvent进行事件的分发
然后到MyLayout的onInterceptTouchEvent拦截事件
1、onInterceptTouchEvent如果return true表示拦截该事件,并在MyLayout中处理
剩下的事件,事件继续由MyLayout进行分发,分发机制同上面的view事件分发机制,但这次分发不会考虑分发给子view,也不会走onInterceptTouchEvent,因为系统已经知道
该套事件MyLayout已经拦截,所以直接在MyLayout中处理

2、如果MyLayout的onInterceptTouchEvent返回false(默认返回false[1]),表示不拦截事件,由MyLayout的子view(以Button为例)的dispatchTouchEvent开始分发事件,分发机制就是上面的view事件分发机制。

public class MyLayout extends LinearLayout {
public MyLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public MyLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
System.out.println("dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}

// 事件发生, 首先由MyLayout的dispatchTouchEvent进行事件的分发
// 然后到MyLayout的onInterceptTouchEvent拦截事件
// 如果return true表示拦截该事件,并在MyLayout中处理
// 剩下的事件继续由MyLayout进行分发,这次分发不会考虑分发给
// 子view,也不会走onInterceptTouchEvent,因为系统已经知道
// 该套事件MyLayout已经拦截,所以直接在MyLayout中处理

// 该demo的执行结果:
// 第一套down、move、up :
// dispatchTouchEvent
// onInterceptTouchEvent
// action_down...
// dispatchTouchEvent
// action_move...
// dispatchTouchEvent
// action_move...
// dispatchTouchEvent
// action_move...
// dispatchTouchEvent
// action_up...

// 再一套:
// dispatchTouchEvent
// onInterceptTouchEvent
// action_down...
// dispatchTouchEvent
// action_move...
// dispatchTouchEvent
// action_move...
// dispatchTouchEvent
// action_move...
// dispatchTouchEvent
// action_up...
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
System.out.println("onInterceptTouchEvent");
if(ev.getAction() == MotionEvent.ACTION_DOWN) {
return true;
}
return super.onInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("action_down...");
break;
case MotionEvent.ACTION_UP:
System.out.println("action_up...");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("action_move...");
break;
}
return true;
}
}


执行的结果:
第一套down、move、up :
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...

再一套:
dispatchTouchEvent
onInterceptTouchEvent
action_down...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_move...
dispatchTouchEvent
action_up...

MyLinearLayout:
public class MyLinearLayout extends LinearLayout{
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
// 这里返回true, 则拦截掉事件,不会再往子view传递,继续调用该view的dispachTouchEvent和onTouch
}
}


MainActivity:
public class MainActivity extends Activity {
private MyLinearLayout mLayout;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout = (MyLinearLayout) findViewById(R.id.layout);
mButton = (Button) findViewById(R.id.click);
mLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("layout touch " + event.getAction());
return false;
}
});
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 因为在MyLinearLayout中已经拦截了事件,所以这里不会输出
System.out.println("button click...");
}
});
}
}


执行结果:
layout touch 0

注意[1] : ListView的onInterceptTouchEvent默认返回的是true,表示拦截了事件。所以在listView中的Button按照普通设置click的方法是不能点击的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息