android下ViewGroup的事件分發和處理

來源:互聯網
上載者:User

標籤:android

先寫個簡單的demo:

布局檔案中一個繼承自ViewGroup的自訂控制項MyLayout包含一個Button:

<RelativeLayout 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">    <com.example.viewgroupdemo.MyLayout        android:id="@+id/layout"        android:layout_width="match_parent"        android:layout_height="match_parent" >        <Button            android:id="@+id/button"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@string/hello_world" />    </com.example.viewgroupdemo.MyLayout></RelativeLayout>


自訂控制項中重寫事件分發的兩個重要方法:onInterceptTouchEvent 和 dispatchTouchEvent

public class MyLayout extends LinearLayout {public MyLayout(Context context, AttributeSet attrs) {super(context, attrs);}//是否攔截事件的傳遞,true:攔截@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {//false:把touch事件傳遞到子控制項return false;}//LinearLayout並沒有重寫dispatchTouchEvent//ViewGroup重寫了View的dispatchTouchEvent方法@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {return super.dispatchTouchEvent(ev);}}
在MainActivity中設定兩個控制項的點擊事件:

layout.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Log.i(tag, "click layout --------");}});button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Log.i(tag, "click button --------");}});

此時點擊Button,由於在外層MyLayout沒有阻止事件的傳遞,所以Button響應並處理了事件,列印"click button"的log

如果在MyLayout的onInterceptTouchEvent 中return true則表示MyLayout阻止了事件的傳遞,此時列印"click layout"

問題:當點擊螢幕時系統如何確定是哪個view被點中呢?

實際上每個view對應螢幕上的一塊矩形地區,當點擊螢幕時系統通過判斷該點屬於哪塊矩形地區來確定哪個view被選中

查看源碼解釋現象:

<pre name="code" class="java"> public boolean dispatchTouchEvent(MotionEvent ev) {        ......        //在按下時處理        if (action == MotionEvent.ACTION_DOWN) {        //先將view對象置為null            if (mMotionTarget != null) {                mMotionTarget = null;            }            //如果事件傳遞沒有被阻止,向內傳遞            if (disallowIntercept || !onInterceptTouchEvent(ev)) {            /**             * 步驟總結:             * //1,找到當前控制項子控制項//2,判斷當前點中點,所在的(x,y)屬於哪個子控制項的矩形地區內//3,判斷當前子控制項是viewgroup的子類對象,還是view的子類對象    //3.1  viewgroup 上述操作再來一遍//3.2  view 嘗試讓當前view去處理這個事件(true,dispatchTouchEvent方法結束,並且返回truefalse,當前沒有傳回值)             */                // 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 View[] children = mChildren;                //擷取當前ViewGroup子節點的個數                final int count = mChildrenCount;                //對當前ViewGroup子節點進行遍曆迴圈,通過判斷點中的點包含在哪個子節點確定哪個View被選中                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)) {                        .......                            //這裡的事件分發即有可能是ViewGroup也可能是View,但最終調用的是view的dispatchTouchEvent方法                            //注意:viewgroup是有重寫過view的view的dispatchTouchEvent方法                             //如果為true,說明這view個子節點處理了事件,事件響應完畢,可參考下一行goole工程師的注釋~~                            //如果是false,則繼續走後續到的邏輯                            if (child.dispatchTouchEvent(ev))  {                                // Event handled, we have a target now.                                mMotionTarget = child;                                return true;                            }                        }                    }                }            }        }        ......省略無關代碼        // The event wasn't an ACTION_DOWN, dispatch it to our target if        // we have one.        final View target = mMotionTarget;        if (target == null) {            // We don't have a target, this means we're handling the            // event as a regular view.            //調用當前對象父view的事件分發規則,注意當前對象為viewgroup對象,所以父view是View            return super.dispatchTouchEvent(ev);        }



android下ViewGroup的事件分發和處理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.