[关闭]
@ZeroGeek 2016-09-22T11:54:53.000000Z 字数 4834 阅读 609

Android的事件传递机制

android


前言

View可以监听交互事件(触碰,点击等),当View与ViewGroup之间重叠时,Android系统是怎么处理这些事件的呢?本文主要分析ACTION_DOWN事件(常用的有ACTION_UP,ACTION_MOVE等)在View之间的传递,涉及下面3个方法:

通过demo看规律

(代码附录在最后,迫不及待来分析吧)自定义了个LogButton,作为View这类。LogLinearLayout,作为ViewGroup这类,加上Activity,全部重写dispatchTouchEvent,onTouchEvent,onInterceptTouchEvent,并捕获ACTION_DOWN和ACTION_UP事件,输出log。布局就是把一个LogButton放入一个LogLinearLayout中。然后在Activity中监听onTouch事件。

首先自定义个LogButton,作为View这类

  1. public class LogButton extends Button {
  2. private static final String TAG = "LogButton";
  3. public LogButton(Context context, AttributeSet attrs) {
  4. super(context, attrs);
  5. }
  6. @Override
  7. public boolean onTouchEvent(MotionEvent event) {
  8. switch (event.getAction()) {
  9. case MotionEvent.ACTION_DOWN:
  10. Log.d(MainActivity.MY_TAG, TAG+" onTouchEvent :ACTION_DOWN");
  11. break;
  12. case MotionEvent.ACTION_UP:
  13. Log.d(MainActivity.MY_TAG, TAG+" onTouchEvent :ACTION_UP");
  14. break;
  15. }
  16. // 注意这里默认是true。
  17. return true;
  18. }
  19. @Override
  20. public boolean dispatchTouchEvent(MotionEvent ev) {
  21. switch (ev.getAction()) {
  22. case MotionEvent.ACTION_DOWN:
  23. Log.d(MainActivity.MY_TAG, TAG+" dispatchTouchEvent :ACTION_DOWN");
  24. break;
  25. case MotionEvent.ACTION_UP:
  26. Log.d(MainActivity.MY_TAG, TAG+" dispatchTouchEvent :ACTION_UP");
  27. break;
  28. }
  29. return super.dispatchTouchEvent(ev);
  30. }
  31. }

然后定义个LogLinearLayout,作为ViewGroup这类

  1. public class LogLinearLayout extends LinearLayout {
  2. private static final String TAG = "LogLinearLayout";
  3. public LogLinearLayout(Context context, AttributeSet attrs) {
  4. super(context, attrs);
  5. }
  6. @Override
  7. public boolean onTouchEvent(MotionEvent event) {
  8. switch (event.getAction()) {
  9. case MotionEvent.ACTION_DOWN:
  10. Log.d(MainActivity.MY_TAG, TAG+" onTouchEvent :ACTION_DOWN");
  11. break;
  12. case MotionEvent.ACTION_UP:
  13. Log.d(MainActivity.MY_TAG, TAG+" onTouchEvent :ACTION_UP");
  14. break;
  15. }
  16. // 这里默认是super.onTouchEvent(event)
  17. return super.onTouchEvent(event);
  18. }
  19. @Override
  20. public boolean onInterceptTouchEvent(MotionEvent ev) {
  21. switch (ev.getAction()) {
  22. case MotionEvent.ACTION_DOWN:
  23. Log.d(MainActivity.MY_TAG, TAG+" onInterceptTouchEvent :ACTION_DOWN");
  24. break;
  25. case MotionEvent.ACTION_UP:
  26. Log.d(MainActivity.MY_TAG, TAG+" onInterceptTouchEvent :ACTION_UP");
  27. break;
  28. }
  29. return super.onInterceptTouchEvent(ev);
  30. }
  31. @Override
  32. public boolean dispatchTouchEvent(MotionEvent ev) {
  33. switch (ev.getAction()) {
  34. case MotionEvent.ACTION_DOWN:
  35. Log.d(MainActivity.MY_TAG, TAG+" dispatchTouchEvent :ACTION_DOWN");
  36. break;
  37. case MotionEvent.ACTION_UP:
  38. Log.d(MainActivity.MY_TAG, TAG+" dispatchTouchEvent :ACTION_UP");
  39. break;
  40. }
  41. return super.dispatchTouchEvent(ev);
  42. }
  43. }

主界面,其实是Activity类实现了Window的一个Callback接口,里面包含这2个方法。

  1. public class MainActivity extends AppCompatActivity {
  2. private static final String TAG = "MainActivity";
  3. public static final String MY_TAG = "zero";
  4. private LogButton btn;
  5. private LogLinearLayout ly;
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. btn = (LogButton) findViewById(R.id.log_btn);
  11. ly = (LogLinearLayout) findViewById(R.id.log_ly);
  12. btn.setOnTouchListener(new View.OnTouchListener() {
  13. @Override
  14. public boolean onTouch(View view, MotionEvent motionEvent) {
  15. switch (motionEvent.getAction()) {
  16. case MotionEvent.ACTION_DOWN:
  17. Log.d(MainActivity.MY_TAG, TAG+" btn onTouch :ACTION_DOWN");
  18. break;
  19. case MotionEvent.ACTION_UP:
  20. Log.d(MainActivity.MY_TAG, TAG+" btn onTouch :ACTION_UP");
  21. break;
  22. }
  23. return false;
  24. }
  25. });
  26. ly.setOnTouchListener(new View.OnTouchListener() {
  27. @Override
  28. public boolean onTouch(View view, MotionEvent motionEvent) {
  29. switch (motionEvent.getAction()) {
  30. case MotionEvent.ACTION_DOWN:
  31. Log.d(MainActivity.MY_TAG, TAG+" layout onTouch :ACTION_DOWN");
  32. break;
  33. case MotionEvent.ACTION_UP:
  34. Log.d(MainActivity.MY_TAG, TAG+" layout onTouch :ACTION_UP");
  35. break;
  36. }
  37. return false;
  38. }
  39. });
  40. }
  41. @Override
  42. public boolean dispatchTouchEvent(MotionEvent ev) {
  43. switch (ev.getAction()) {
  44. case MotionEvent.ACTION_DOWN:
  45. Log.d(MainActivity.MY_TAG, TAG+" dispatchTouchEvent :ACTION_DOWN");
  46. break;
  47. case MotionEvent.ACTION_UP:
  48. Log.d(MainActivity.MY_TAG, TAG+" dispatchTouchEvent :ACTION_UP");
  49. break;
  50. }
  51. return super.dispatchTouchEvent(ev);
  52. }
  53. @Override
  54. public boolean onTouchEvent(MotionEvent event) {
  55. switch (event.getAction()) {
  56. case MotionEvent.ACTION_DOWN:
  57. Log.d(MainActivity.MY_TAG, TAG+" onTouchEvent :ACTION_DOWN");
  58. break;
  59. case MotionEvent.ACTION_UP:
  60. Log.d(MainActivity.MY_TAG, TAG+" onTouchEvent :ACTION_UP");
  61. break;
  62. }
  63. return super.onTouchEvent(event);
  64. }
  65. }

布局文件

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical"
  6. tools:context="com.zero.eventdemo.MainActivity">
  7. <com.zero.eventdemo.LogLinearLayout
  8. android:id="@+id/log_ly"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content">
  11. <com.zero.eventdemo.LogButton
  12. android:id="@+id/log_btn"
  13. android:layout_width="200dp"
  14. android:layout_height="wrap_content"
  15. android:text="log button"/>
  16. </com.zero.eventdemo.LogLinearLayout>
  17. </LinearLayout>

参考

  1. 图解 Android 事件分发机制
  2. 公共技术点之 View 事件传递
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注