Android 事件分發

一、事件分發機制java

      用戶點擊產生一個MotionEvent,系統把這個事件分發給具體的view消費android

二、MotionEvent介紹json

     手勢接觸屏幕產生的事件 app

     MotionEvent對象操做有:ide

                                             一、MotionEvent.ACTION_DOWN   手勢按下,是全部觸發操做中最開始的動做佈局

                                               二、MotionEvent.ACTION_UP 手勢向上,是全部觸發操做最後的動做spa

                                               三、MotionEvent.ACTION_MOVE 手勢按下後沒有收回code

                                             四、MotionEvent.ACTION_CANCEL  事件結束 理論上是ACTION_UP 後執行,但也有多是非人爲因素致使的.xml

三、事件分發的本質對象

將MotinEvent傳遞到某個具體的view處理的過程

四、事件分發的對象及分發順序

Activity ViewGroup View

Activity: 控制生命週期、處理事件

             統籌視圖的現實和添加、經過其它回調方法與Window、View交互.

View:全部UI組件的基類

ViewGroup:一組view的組合,其自己也是view的子類,是android佈局的全部父類.比view多了可包含子view和定義佈局參數的功能.

 

五、事件分發的過程協助者

協助者:dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()

dispatchTouchEvent():用來進行事件的分發,當點擊事件可以傳遞給當前view,該方法就會被調用.返回結果受到當前View的TouchEvent和下級view的dispatchTouchEvent方法影響,表示是否消費當前的事件

onTouchEvent:在dispatchTouchEvent方法內部調用,用來處理事件,返回結果表示是否消耗當前事件,若是不消耗,則在同一個事件序列中,當前view沒法再接受到後續的事件隊列。並且onTouchEvent返回值由clickable和longclickable共同決定

onInterceptTouchEvent():在dispatchTouchEvent()內部調用.用來表示是否攔截當前的事件.若是當前view攔截了某個事件,那麼在同一個事件序列當中,此方法不會被調用,返回結果表示是否攔截當前事件。

 

六、代碼說明演示

ViewGroup 表明 -》新建類DemoLayout 繼承LinearLayout

public class DemoLayout extends LinearLayout {
    private static final String TAG = "DemoLayout";
    public DemoLayout(Context context) {
        super(context);
    }

    public DemoLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public DemoLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public DemoLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
//        父容器的分發事件
        Log.i(TAG, "----父容器的分發事件"+ev.getAction());
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:

                break;

            case MotionEvent.ACTION_MOVE:

                break;

            case MotionEvent.ACTION_UP:

                break;

            case MotionEvent.ACTION_CANCEL:

                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //父容器的攔截事件
        Log.i(TAG, "----父容器的攔截事件"+ev.getAction());
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:

                break;

            case MotionEvent.ACTION_MOVE:

                break;

            case MotionEvent.ACTION_UP:

                break;

            case MotionEvent.ACTION_CANCEL:

                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //父容器的觸摸事件
        Log.i(TAG, "----父容器的觸摸事件"+ev.getAction());
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:

                break;

            case MotionEvent.ACTION_MOVE:

                break;

            case MotionEvent.ACTION_UP:

                break;

            case MotionEvent.ACTION_CANCEL:

                break;
        }
        return super.onTouchEvent(ev);
    }
}

 

View 表明-》 新建類View集成Button

public class View extends android.support.v7.widget.AppCompatButton {
    private static final String TAG = "View";
    public View(Context context) {
        super(context);
    }

    public View(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public View(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i(TAG, "----子容器的分發事件"+ event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "----子容器的觸摸事件"+event.getAction());
        return super.onTouchEvent(event);
    }

}

            操做準備:在layout佈局中建立DemoLayout佈局,包含View控件

<com.example.sunyuanfei.myapplication.DemoLayout
    android:layout_width="500dp"
    android:layout_height="500dp"
    android:clickable="true"
    android:background="#000000">

    <com.example.sunyuanfei.myapplication.View
        android:id="@+id/view_touch"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="事件分發"/>
</com.example.sunyuanfei.myapplication.DemoLayout>

初次運行看下運行流程:

沒有攔截時

父容器把事件交給了子容器處理 dispatchTouchEvent進行事件分發 onInterceptTouchEvent沒有攔截 子容器執行dispatchTouchEvent事件分發,再執行onTouchEvent事件

攔截後 代碼和流程

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    //父容器的攔截事件
    Log.i(TAG, "----父容器的攔截事件"+ev.getAction());
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:

            break;

        case MotionEvent.ACTION_MOVE:

            break;

        case MotionEvent.ACTION_UP:

            break;

        case MotionEvent.ACTION_CANCEL:

            break;
    }
    return true;
}

DemoLayout  dispatchTouchEvent進行事件分發 onInterceptTouchEvent攔截  父容器執行onTouchEvent,(備註:父容器clickable默認值是false即表明onTouchEvent 返回false,後續操做系列Action_UP不會執行,以下圖,因此在xml中要聲明clickable="true").從上看出攔截事件onIntercepeTpuchEvent不會再執行,只會被消費一次

若子容器不消費onTouchEvent,則事件會傳遞給父容器,並且不會接受後續操做,父容器onInterceptTouchEvent也不會再執行.一樣若子容器在xml聲明clickable="false"也就表明着子容器的onTouchEvent返回false。(備註操做:事件系列操做指的是按下ACTION_DOWN、移動ACTION_MOVE、擡起ACTION_UP,所謂後續操做如圖子容器的ACTION_UP就沒有再執行了)

@Override
public boolean onTouchEvent(MotionEvent event) {
    Log.i(TAG, "----子容器的觸摸事件"+event.getAction());
    return false;
}

若子容器的onTouchEvent返回false,onClick方法也是不可以執行的,由於回調方法onClick()是在onTouchEvent中執行的

 

總結

相關文章
相關標籤/搜索