Android自己定义组件系列【6】——进阶实践(3)
上一篇《Android自己定義組件系列【5】——進(jìn)階實(shí)踐(2)》繼續(xù)對(duì)任老師的《可下拉的PinnedHeaderExpandableListView的實(shí)現(xiàn)》進(jìn)行了分析,這一篇計(jì)劃中間插一段“知識(shí)點(diǎn)”,對(duì)Android中的事件分發(fā)機(jī)制進(jìn)行解析。
細(xì)心的朋友可能會(huì)發(fā)現(xiàn)。打開大牛寫的Android項(xiàng)目,里面非常多組件都是自己定義的(這就是為什么界面和體驗(yàn)這么吸引你的原因)。可是要靈活的去自己定義組件就必須對(duì)手勢(shì)(也就是各種監(jiān)聽(tīng))必須熟悉,能處理好事件之間的關(guān)系。
先看一段代碼:
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {Log.i(TAG, "onClick");}});button.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.i(TAG, "onTouch down");break;case MotionEvent.ACTION_MOVE:Log.i(TAG, "onTouch move");break;case MotionEvent.ACTION_UP:Log.i(TAG, "onTouch up");break;default:break;}return false;}});}能夠看到onTouch方法會(huì)被先調(diào)用,然后才調(diào)用onClick方法。假設(shè)我們將上面onTouch方法的返回值改為true,則onClick方法不會(huì)被調(diào)用。事件將被onTouch方法消費(fèi)。
還記得前幾篇文章中都會(huì)使用一個(gè)dispatchTouchEvent的方法嗎.
public boolean dispatchTouchEvent(MotionEvent event) {if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&mOnTouchListener.onTouch(this, event)) {return true;}return onTouchEvent(event); }能夠看到在dispatchTouchEvent中調(diào)用了onTouch方法,所以會(huì)先于onClick方法調(diào)用。假設(shè)onTouch返回true后dispatcheTouchEvent就會(huì)直接返回true則不會(huì)再運(yùn)行其它方法。
在Android系統(tǒng)中每一個(gè)ViewGroup子類都具有例如以下三個(gè)方法:
public boolean dispatchTouchEvent(MotionEvent event) ?:用來(lái)分發(fā)TouchEvent
public boolean onInterceptTouchEvent(MotionEvent event) :用來(lái)攔截TouchEvent
public boolean onTouchEvent(MotionEvent event) :處理TouchEvent
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <com.kris.touch.widget.TouchView android:id="@+id/view_out" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#fff" android:gravity="center"> <com.kris.touch.widget.TouchView android:id="@+id/view_mid" android:layout_width="300px" android:layout_height="400px" android:background="#f00" android:gravity="center"> <com.kris.touch.widget.TouchView android:id="@+id/view_center" android:layout_width="150px" android:layout_height="150px" android:background="#000" android:gravity="center" android:clickable="true"> </com.kris.touch.widget.TouchView> </com.kris.touch.widget.TouchView> </com.kris.touch.widget.TouchView> </LinearLayout>
首先觸摸事件(ACTION_DOWN)發(fā)生后。系統(tǒng)調(diào)用Activity的dispatchTouchEvent方法,分發(fā)事件。依據(jù)觸摸事件的坐標(biāo),將此事件傳遞給out(最外層)的dispatchTouchEvent處理。out則調(diào)用onInterceptTouchEvent方法推斷事件是否由自己來(lái)處理。還是向下傳遞給子View.假設(shè)out不處理該事件會(huì)依據(jù)事件產(chǎn)生坐標(biāo)分發(fā)給它的直接子View.
圖中center組件是可點(diǎn)擊的(clickable)組件。表示能處理Touch事件,所以center中的onInterceptTouchEvent方法將事件傳遞給center
TouchEvent中。假設(shè)返回值是true,則說(shuō)明消耗(消費(fèi))了這個(gè)事件,不會(huì)再向下傳遞。假設(shè)返回值是false,則沒(méi)有消耗事件,會(huì)繼續(xù)傳遞下去。假設(shè)center中不會(huì)處理事件(android:clickable="false"),事件不會(huì)被center的onTouchEvent消費(fèi),則事件會(huì)層層逆向回到activity。
關(guān)于事件分發(fā)機(jī)制就先了解到這里,下一篇接著分析......
總結(jié)
以上是生活随笔為你收集整理的Android自己定义组件系列【6】——进阶实践(3)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C# 7编程模式与实践
- 下一篇: 微服务,微架构[五]之springboo