編輯:關於Android編程
今天給大家代碼ViewGroup事件分發的源碼解析~~凡是自定義ViewGroup實現各種滑動效果的,不可避免的會出現很多事件的沖突,對ViewGroup事件分發機制的了解,也有益於大家了解沖突產生的原因,以及對沖突進行處理~
首先我們接著上一篇的代碼,在代碼中添加一個自定義的LinearLayout:
package com.example.zhy_event03; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.LinearLayout; public class MyLinearLayout extends LinearLayout { private static final String TAG = MyLinearLayout.class.getSimpleName(); public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "dispatchTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "dispatchTouchEvent ACTION_UP"); break; default: break; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "onTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "onTouchEvent ACTION_UP"); break; default: break; } return super.onTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "onInterceptTouchEvent ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "onInterceptTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "onInterceptTouchEvent ACTION_UP"); break; default: break; } return super.onInterceptTouchEvent(ev); } @Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { Log.e(TAG, "requestDisallowInterceptTouchEvent "); super.requestDisallowInterceptTouchEvent(disallowIntercept); } }
繼承LinearLayout,然後復寫了與事件分發機制有關的代碼,添加上了日志的打印~
然後看我們的布局文件:
<com.example.zhy_event03.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <com.example.zhy_event03.MyButton android:id="@+id/id_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="click me" /> </com.example.zhy_event03.MyLinearLayout>
MyLinearLayout中包含一個MyButton,MyButton都上篇博客中已經出現過,這裡就不再貼代碼了,不清楚可以去查看~
然後MainActivity就是直接加載布局,沒有任何代碼~~~
直接運行我們的代碼,然後點擊我們的Button,依然是有意的MOVE一下,不然不會觸發MOVE事件,看一下日志的輸出:
09-06 09:57:27.287: E/MyLinearLayout(959): dispatchTouchEvent ACTION_DOWN 09-06 09:57:27.287: E/MyLinearLayout(959): onInterceptTouchEvent ACTION_DOWN 09-06 09:57:27.287: E/MyButton(959): dispatchTouchEvent ACTION_DOWN 09-06 09:57:27.297: E/MyButton(959): onTouchEvent ACTION_DOWN 09-06 09:57:27.297: E/MyButton(959): onTouchEvent ACTION_MOVE 09-06 09:57:27.327: E/MyLinearLayout(959): dispatchTouchEvent ACTION_MOVE 09-06 09:57:27.327: E/MyLinearLayout(959): onInterceptTouchEvent ACTION_MOVE 09-06 09:57:27.337: E/MyButton(959): dispatchTouchEvent ACTION_MOVE 09-06 09:57:27.337: E/MyButton(959): onTouchEvent ACTION_MOVE 09-06 09:57:27.457: E/MyLinearLayout(959): dispatchTouchEvent ACTION_UP 09-06 09:57:27.457: E/MyLinearLayout(959): onInterceptTouchEvent ACTION_UP 09-06 09:57:27.457: E/MyButton(959): dispatchTouchEvent ACTION_UP 09-06 09:57:27.457: E/MyButton(959): onTouchEvent ACTION_UP
可以看到大體的事件流程為:
MyLinearLayout的dispatchTouchEvent -> MyLinearLayout的onInterceptTouchEvent -> MyButton的dispatchTouchEvent ->Mybutton的onTouchEvent
可以看出,在View上觸發事件,最先捕獲到事件的為View所在的ViewGroup,然後才會到View自身~
下面我們按照日志的輸出,進入源碼~
ViewGroup - dispatchTouchEvent
首先是ViewGroup的dispatchTouchEvent方法:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!onFilterTouchEventForSecurity(ev)) { return false; } final int action = ev.getAction(); final float xf = ev.getX(); final float yf = ev.getY(); final float scrolledXFloat = xf + mScrollX; final float scrolledYFloat = yf + mScrollY; final Rect frame = mTempRect; boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (action == MotionEvent.ACTION_DOWN) { if (mMotionTarget != null) { // this is weird, we got a pen down, but we thought it was // already down! // XXX: We should probably send an ACTION_UP to the current // target. mMotionTarget = null; } // If we're disallowing intercept or if we're allowing and we didn't // intercept if (disallowIntercept || !onInterceptTouchEvent(ev)) { // reset this event's action (just to protect ourselves) ev.setAction(MotionEvent.ACTION_DOWN); // We know we want to dispatch the event down, find a child // who can handle it, start with the front-most child. final int scrolledXInt = (int) scrolledXFloat; final int scrolledYInt = (int) scrolledYFloat; final View[] children = mChildren; final int count = mChildrenCount; for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(scrolledXInt, scrolledYInt)) { // offset the event to the view's coordinate system final float xc = scrolledXFloat - child.mLeft; final float yc = scrolledYFloat - child.mTop; ev.setLocation(xc, yc); child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; if (child.dispatchTouchEvent(ev)) { // Event handled, we have a target now. mMotionTarget = child; return true; } // The event didn't get handled, try the next view. // Don't reset the event's location, it's not // necessary here. } } } } } ....//other code omitted
代碼比較長,決定分段貼出,首先貼出的是ACTION_DOWN事件相關的代碼。
16行:進入ACTION_DOWN的處理
17-23行:將mMotionTarget置為null
26行:進行判斷:if(disallowIntercept || !onInterceptTouchEvent(ev))
Android有很多種drawable類型,除了前幾篇詳細講解的shape、selector、layer-list,還有上一篇提到的color、bitmap、
Android開發四大組件分別是:活動(Activity):用於表現功能。服務(Service):後台運行服務,不提供界面呈現。廣播接收器(BroadcastReceiv
寫在前面的話:接觸Android的時間也不短了,聽了視頻、看了書、敲了代碼,寫了博客,做了demo。。。但是想做出一款優秀的APP(哪怕是封裝一個不錯的功能)還有很長的路
什麼是Android UDP?UDP是User Datagram Protocol的簡稱,中文名是用戶數據包協議,是OSI參考模型中一種無連接的傳輸層協議,提供面向事務的