首页 > 代码库 > android事件分发机制总结
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 : MyLinearlayout为例;
首先由ViewGroup(所有容器view的父类)的dispatchTouchEvent分发事件,MyLinearlayout的onInterceptTouchEvent首先接收到事件,如果onInterceptTouchEvent返回true,表示拦截该事件,由MyLinearlayout的dispatchTouchEvent在MyLinearlayout进行事件的分发,分发机制同上面的view事件分发机制;如果MyLinearLayout的onInterceptTouchEvent返回false(默认返回false[1]),表示不拦截事件,由MyLinearLayout的子view(以Button为例)的dispatchTouchEvent开始分发事件,分发机制就是上面的view事件分发机制。
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的方法是不能点击的。
android事件分发机制总结