Android事件機制深入探討(二)

這篇博文是基於上篇《Android事件機制深入探討(一)》基礎擴展而來,建議讀本文之前先閱讀上一篇。

上篇我們學習了Android的事件傳遞機制,這裏就假裝大家都懂了啊,接下來我們繼續深入學習事件的傳遞機制,首先我們把原來的demo中的Activity、CustomLinearLayout、CustomTextView類中的dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent方法的return語句復原(上一篇我們爲了加深理解改了代碼查看效果),即改爲:

return super.dispatchTouchEvent(event);
return super.onInterceptTouchEvent(event);
return super.onTouchEvent(event);

事件的分發流程很複雜,接下來我們就引入setOnTouchListener和setOnClickListener來深入講解,首先爲ViewGroup和ViewActivity添加setOnTouchListener方法並打印日誌,完整代碼如下:

public class TouchEventActivity extends AppCompatActivity {

    private CustomLinearLayout mCustomLinearLayout;
    private CustomTextView mCustomTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_touch_event);

        mCustomLinearLayout = (CustomLinearLayout) findViewById(R.id.ll_touch_layout);
        mCustomTextView = (CustomTextView) findViewById(R.id.tv_touch_content);

        mCustomLinearLayout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e(TouchEventActivity.this.getClass().getSimpleName(), "這是ViewGroup的--->onTouch");
                return false;
            }
        });
        mCustomTextView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e(getClass().getSimpleName(), "這是View的--->onTouch");
                return false;
            }
        });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e(getClass().getSimpleName(), "這是Activity的--->dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(getClass().getSimpleName(), "這是Activity的--->onTouchEvent");
        return super.onTouchEvent(event);
    }
}

運行,點擊,日誌如下:
事件分發日誌
這裏看到的跟我們上篇博文的運行效果差不多,但還是有差別的,ViewGroup和View我們所設置的setOnTouchListener被執行了,即在執行事件消費(onTouchEvent)方法前會先執行用戶設置的onTouch方法。細心的同學也發現了,我們在onTouch方法裏返回默認值false,如果我們把它改爲返回true呢,改一下代碼:

    mCustomLinearLayout.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.e(TouchEventActivity.this.getClass().getSimpleName(), "這是ViewGroup的--->onTouch");
            return true;
        }
    });
    mCustomTextView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.e(TouchEventActivity.this.getClass().getSimpleName(), "這是View的--->onTouch");
            return true;
        }
    });

運行,點擊,日誌如下:
事件分發日誌
我們從日誌可以看出ACTION_DOWN、ACIONT_MOVE、ACTION_UP三個事件都會傳遞到View裏,但是都會在onTouch方法裏終止傳遞,且並沒有執行onTouchEvent事件消費方法,所以結論是:用戶設置的setOnTouchListener會在onTouchEvent方法前調用,並且onTouch的返回值是false的話,會繼續執行onTouchEvent方法,如果返回true的話,表明該事件被消費了,事件終止傳遞(我們在ViewGroup也設置了setOnTouchListener方法,但沒有被執行,也是這個原因),並不會執行onTouchEvent方法。

我們再來驗證一下,現在我們把View(CustomTextView)的onTouch返回值改回false,然後ViewGroup(CustomLinearLayout)的onTouch返回值保持true不變,代碼如下:

    mCustomLinearLayout.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.e(TouchEventActivity.this.getClass().getSimpleName(), "這是ViewGroup的--->onTouch");
            return true;
        }
    });
    mCustomTextView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.e(TouchEventActivity.this.getClass().getSimpleName(), "這是View的--->onTouch");
            return false;
        }
    });

運行,打印日誌,如下:
事件分發日誌

ACTION_DOWN分發到View的onTouch,此時返回值爲false,沒有消費事件,繼續執行onTouchEvent方法,該返回一樣返回false,事件再往上傳遞給ViewGroup的onTouchEvent方法,因爲我們爲ViewGroup設置了setOnTouchListener,所以在執行onTouchEvent之前會先執行onTouch,而我們在onTouch方法返回了true,表明該事件被消費,接着傳遞終止,所以ViewGroup的onTouchEvent方法並沒有被執行。

由於ACTION_DOWN的事件被ViewGroup消費掉了,所以接下來的ACTION_MOVE、ACTION_UP事件就直接傳遞給ViewGroup,View就無法接收到事件了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章