這篇博文是基於上篇《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就無法接收到事件了。