Android Touch event transmission mechanism, androidtouch
I didn't know much about android's event transfer mechanism. Today, I am not busy. I have to take the time to understand this knowledge. In this article, I will use the demo to analyze android's event transfer mechanism.
In the process of event transfer, the following three methods are required:
1. dispatchTouchEvent: touchEvent is distributed to TouchEvent. If the returned value is true, touchEvent is processed by the current View, and the event is not passed to the lower layer (including subsequent onInterceptTouchEvent and onTouchEvent ),
DispatchTouchEvent will receive subsequent ACTION_MOVE and ACTION_UP events
2. onInterceptTouchEvent: The touchEvent is intercepted. If true is returned, the current View intercepts the touchEvent. Then, the event is handed over to the onTouchEvent of the current View for processing.
3. onTouchEvent processes TouchEvent. If true is returned, this event is consumed by the current View. Only after the previous event is consumed can subsequent events be received.
To understand how android transmits view events at different layers, I wrote a small demo to analyze the event transfer between activities, viewgroups, and views.
First, let's take a look at the code. A custom View draws a rectangle and adds logs to dispatchTouchEvent and onTouchEvent for easy parsing.
1 public class DrawRectView extends View { 2 3 private Paint mPaint; 4 5 public DrawRectView(Context context) { 6 super(context); 7 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 8 } 9 10 public DrawRectView(Context context, AttributeSet set) {11 super(context, set);12 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);13 }14 15 @Override16 public boolean dispatchTouchEvent(MotionEvent event) {17 Log.v(LogUtils.TAG, "DrawRectView dispatchTouchEvent action=" + event.getAction());18 return super.dispatchTouchEvent(event);19 }20 21 22 @Override23 protected void onDraw(Canvas canvas) {24 super.onDraw(canvas);25 mPaint.setColor(Color.YELLOW);26 canvas.drawRect(0, 0, 300, 300, mPaint);27 }28 29 @Override30 public boolean onTouchEvent(MotionEvent event) {31 Log.v(LogUtils.TAG, "DrawRectView onTouchEvent action=" + event.getAction());32 return super.onTouchEvent(event);33 }34 }
Custom Layout, also add log to the relevant TouchEvent Method
1 public class MyLayout extends RelativeLayout { 2 3 public MyLayout(Context context, AttributeSet attrs) { 4 super(context, attrs); 5 } 6 7 @Override 8 public boolean dispatchTouchEvent(MotionEvent ev) { 9 Log.v(LogUtils.TAG, "MyLayout dispatchTouchEvent action=" + ev.getAction());10 return super.dispatchTouchEvent(ev);11 }12 13 @Override14 public boolean onInterceptTouchEvent(MotionEvent ev) {15 Log.v(LogUtils.TAG, "MyLayout onInterceptTouchEvent action=" + ev.getAction());16 return super.onInterceptTouchEvent(ev);17 }18 19 @Override20 public boolean onTouchEvent(MotionEvent event) {21 Log.v(LogUtils.TAG, "MyLayout onTouchEvent event=" + event.getAction());22 return super.onTouchEvent(event);23 }
Next is the layout of Activity and activity.
1 public class TouchTestActivity extends Activity { 2 3 private DrawRectView mDrawRectView; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.touch_test_activity); 9 10 mDrawRectView = (DrawRectView) findViewById(R.id.draw_rect_view);11 mDrawRectView.setOnTouchListener(new OnTouchListener() {12 @Override13 public boolean onTouch(View v, MotionEvent event) {14 Log.v(LogUtils.TAG, "mDrawRectView OnTouchListener action=" + event.getAction());15 return false;16 }17 });18 }19 20 @Override21 public boolean dispatchTouchEvent(MotionEvent ev) {22 Log.v(LogUtils.TAG, "TouchTestActivity dispatchTouchEvent action=" + ev.getAction());23 return super.dispatchTouchEvent(ev);24 }25 26 @Override27 public boolean onTouchEvent(MotionEvent event) {28 Log.v(LogUtils.TAG, "TouchTestActivity onTouchEvent action=" + event.getAction());29 return super.onTouchEvent(event);30 }31 }
1 <com.yangy.test.custom_view.MyLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" > 4 5 <com.yangy.test.custom_view.DrawRectView 6 android:id="@+id/draw_rect_view" 7 android:layout_width="300dp" 8 android:layout_height="300dp" 9 android:layout_centerInParent="true" />10 11 </com.yangy.test.custom_view.MyLayout>
When we press the rectangular DrawRectView, we can see the printed log information as follows. The Android Touch event is passed from top to bottom, Activity --> ViewGroup --> View
11-24 15:19:40. 659: V/-- DEBUG -- (32570): TouchTestActivity dispatchTouchEvent action = ACTION_DOWN
11-24 15:19:40. 659: V/-- DEBUG -- (32570): MyLayout dispatchTouchEvent action = ACTION_DOWN
11-24 15:19:40. 659: V/-- DEBUG -- (32570): MyLayout onInterceptTouchEvent action = ACTION_DOWN
11-24 15:19:40. 659: V/-- DEBUG -- (32570): DrawRectView dispatchTouchEvent action = ACTION_DOWN
11-24 15:19:40. 659: V/-- DEBUG -- (32570): mDrawRectView OnTouchListener action = ACTION_DOWN
11-24 15:19:40. 669: V/-- DEBUG -- (32570): DrawRectView onTouchEvent action = ACTION_DOWN
11-24 15:19:40. 669: V/-- DEBUG -- (32570): MyLayout onTouchEvent event = ACTION_DOWN
11-24 15:19:40. 669: V/-- DEBUG -- (32570): TouchTestActivity onTouchEvent action = ACTION_DOWN
11-24 15:19:40. 689: V/-- DEBUG -- (32570): TouchTestActivity dispatchTouchEvent action = ACTION_UP
11-24 15:19:40. 689: V/-- DEBUG -- (32570): TouchTestActivity onTouchEvent action = ACTION_UP
Based on the log information, we also know the entire View event transfer process, which can be expressed. It is worth noting that no View consumes ACTION_DOWN events,
Therefore, the subsequent ACTION_MOVE and ACTION_UP events will not be passed down, which can be seen from the log.
In this case, the onTouchEvent method of DrawRectView is returned to be true. Then, let's look at the log.
11-24 16:04:03. 159: V/-- DEBUG -- (3037): TouchTestActivity dispatchTouchEvent action = ACTION_DOWN
11-24 16:04:03. 159: V/-- DEBUG -- (3037): MyLayout dispatchTouchEvent action = ACTION_DOWN
11-24 16:04:03. 159: V/-- DEBUG -- (3037): MyLayout onInterceptTouchEvent action = ACTION_DOWN
11-24 16:04:03. 159: V/-- DEBUG -- (3037): DrawRectView dispatchTouchEvent action = ACTION_DOWN
11-24 16:04:03. 159: V/-- DEBUG -- (3037): mDrawRectView OnTouchListener action = ACTION_DOWN
11-24 16:04:03. 159: V/-- DEBUG -- (3037): DrawRectView onTouchEvent action = ACTION_DOWN
11-24 16:04:03. 219: V/-- DEBUG -- (3037): TouchTestActivity dispatchTouchEvent action = ACTION_MOVE
11-24 16:04:03. 219: V/-- DEBUG -- (3037): MyLayout dispatchTouchEvent action = ACTION_MOVE
11-24 16:04:03. 219: V/-- DEBUG -- (3037): MyLayout onInterceptTouchEvent action = ACTION_MOVE
11-24 16:04:03. 219: V/-- DEBUG -- (3037): DrawRectView dispatchTouchEvent action = ACTION_MOVE
11-24 16:04:03. 219: V/-- DEBUG -- (3037): mDrawRectView OnTouchListener action = ACTION_MOVE
11-24 16:04:03. 219: V/-- DEBUG -- (3037): DrawRectView onTouchEvent action = ACTION_MOVE
11-24 16:04:03. 249: V/-- DEBUG -- (3037): TouchTestActivity dispatchTouchEvent action = ACTION_UP
11-24 16:04:03. 249: V/-- DEBUG -- (3037): MyLayout dispatchTouchEvent action = ACTION_UP
11-24 16:04:03. 249: V/-- DEBUG -- (3037): MyLayout onInterceptTouchEvent action = ACTION_UP
11-24 16:04:03. 249: V/-- DEBUG -- (3037): DrawRectView dispatchTouchEvent action = ACTION_UP
11-24 16:04:03. 249: V/-- DEBUG -- (3037): mDrawRectView OnTouchListener action = ACTION_UP
11-24 16:04:03. 249: V/-- DEBUG -- (3037): DrawRectView onTouchEvent action = ACTION_UP
It seems that after the onTouchEvent method of DrawRectView consumes the ACTION_DOWN event, both ACTION_MOVE and ACTION_UP are passed. Because the event is consumed, onTouchEvent will not be passed up.
What if the TouchEvent event is intercepted in ViewGroup:
After the instructions in this article, I believe you have a better understanding of the android event transfer mechanism.