編輯:關於Android編程
在前一篇文章中,我主要講解了Android源碼中的Touch事件的傳遞過程,現在我想使用一個demo以及一個實例來學習一下Andorid中的Touch事件處理過程。
在Android系統中,和Touch事件分發和處理緊密相關的三個函數如下:這三個方法主要存在於ViewGroup,View,Activity中,具體情況如下圖:
下面我們就使用一個demo來看看這些方法的執行流程:
ViewGroup
View
Activity
dispatchTouchEvent
有
有
有
onInterceptTouchEvent
有
無
無
onTouchEvent
有
有
有
public class MyLayoutFirst extends LinearLayout { private static final String TAG = MyLayoutFirst; public MyLayoutFirst(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.w(yzy, MyLayoutFirst->onInterceptTouchEvent->+MyUtils.getActionName(ev)); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(yzy, MyLayoutFirst->onTouchEvent->+MyUtils.getActionName(event)); return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i(yzy, MyLayoutFirst->dispatchTouchEvent->+MyUtils.getActionName(ev)); return super.dispatchTouchEvent(ev); } }
public class MyLayoutSecond extends LinearLayout { private static final String TAG = MyLayoutSecond; public MyLayoutSecond(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(yzy, MyLayoutSecond->MyLayoutSecond->+MyUtils.getActionName(event)); return super.onTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.w(yzy, MyLayoutSecond->onInterceptTouchEvent->+MyUtils.getActionName(ev)); return super.onInterceptTouchEvent(ev); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i(yzy, MyLayoutSecond->dispatchTouchEvent->+MyUtils.getActionName(ev)); return super.dispatchTouchEvent(ev); } }
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.i(yzy, MainActivity->dispatchTouchEvent->+MyUtils.getActionName(ev)); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e(yzy, MainActivity->onTouchEvent->+MyUtils.getActionName(event)); return super.onTouchEvent(event); } }
public class MyUtils { private static final String TAG = MyUtils; public static String getActionName(MotionEvent event) { String name=; switch(event.getAction()) { case MotionEvent.ACTION_DOWN: name=ACTION_DOWN; break; case MotionEvent.ACTION_MOVE: name=ACTION_MOVE; break; case MotionEvent.ACTION_UP: name=ACTION_UP; break; } return name; } }
其中藍色部分是MyLayoutSecond.java ,紅色部分是MyLayoutFirst.java
現在我點擊一下藍色部分:運行結果如圖:
從圖中可以看出,事件最先被Activity捕獲,然後分發給 MyLayoutFirst,MyLayoutFirst首先調用自身的onInterceptTouchEvent判斷是否將該事件攔截,由於默認返回是false,所以沒有攔截,從而事件分發給了MyLayoutSecond,MyLayoutSecond同樣通過dispatchTouchEvent分發出去,分發出去之前同樣檢查是否被攔截,默認都是沒有被攔截的,但是由於MyLayoutSecond是沒有子視圖的,所有最終事件有自己處理,調用自身的onTouchEvent方法,由於該方法默認返回的是false,所以認為此事件是沒有被消費掉的,繼續傳遞到了MyLayoutFirst中,同樣也沒有消費這個事件,最終傳遞到了Mainactivity,繼續往後看發現後面的ACTION_MOVE和ACTION_UP並沒有傳入MyLayoutFirst和MyLayoutSecond,這是因為一旦某一個事件沒有被處理,後面的事件是不會被分發的。所以ACTION_MOVE和ACTION_UP直接被MainActivity處理掉了。
下面再看第二種情況:
MainActivity
MyLayoutFirst
MyLayoutSecond
dispatchTouchEvent
super.dispatchTouchEvent
super.dispatchTouchEvent
super.dispatchTouchEvent
onInterceptTouchEvent
--
true
super.onInterceptTouchEvent(ev)
onTouchEvent
super.onTouchEvent
super.onTouchEvent
super.onTouchEvent
運行結果如下:
從圖中可以看出,事件傳遞到了MyLayoutFirst後沒有分發到MyLayoutSecond,直接調用自身的onTouchEvent,由於返回的是false,導致事件沒有消費,最終傳遞給了MainActivity,
而且後續事件也沒有傳遞到MyLayoutFirst和MyLayoutSecond,直接被MainActivity處理
第三種情況:
MainActivity
MyLayoutFirst
MyLayoutSecond
dispatchTouchEvent
super.dispatchTouchEvent
super.dispatchTouchEvent
super.dispatchTouchEvent
onInterceptTouchEvent
--
true
super.onInterceptTouchEvent(ev)
onTouchEvent
super.onTouchEvent
true
super.onTouchEvent
運行結果:
和情況二不同的是MyLayoutFirst的onTouchEvent返回了true,也就是說MyLayoutFirst消費了此事件,所以ACTION_DOWN也沒有再傳給MainActivity,並且ACTION_MOVE和ACTION_UP
均傳給了MyLayoutFirst
第四中情況:
MainActivity
MyLayoutFirst
MyLayoutSecond
dispatchTouchEvent
super.dispatchTouchEvent
super.dispatchTouchEvent
super.dispatchTouchEvent
onInterceptTouchEvent
--
super.onInterceptTouchEvent(ev)
super.onInterceptTouchEvent(ev)
onTouchEvent
super.onTouchEvent
super.onTouchEven
true
運行結果:
發現所有的事件都是傳遞到了MyLayoutSecond後被消費了
其實還有很多其他組合方式,大家如果又興趣可以自己嘗試改變每個函數的返回值,查看打印結果,這裡我就不一一列舉了。。。。。
最後我會提供一個小demo演示如何解決滑動沖突,背景如下:
一個ViewPager裡面包含兩個Framgent,有一個Fragment裡面有一個HorizontalListView ,如何滑動沖突?
我就貼出關鍵代碼吧
horizontal=(HorizontalListView)view.findViewById(R.id.hscroll); horizontal.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View arg0, MotionEvent event) { if(event.getAction()==MotionEvent.ACTION_DOWN) { parent.requestDisallowInterceptTouchEvent(true); }else if(event.getAction()==MotionEvent.ACTION_UP) { parent.requestDisallowInterceptTouchEvent(false); } return false; } });
最近有人讓我幫忙實現一個如下圖所示的效果 需求:標題欄本來是在banner的下方,當滑動下面的RecyclerView的時候標題欄會隨著向上移動,但是當標題欄移動到頂
一、安裝目錄分析 最近在做手機項目時,涉及很多本地文件管理方面的內容,比如用戶的頭像、下載的圖片、視頻等等,將這些文件緩存在本地,必須設計一個合理的組織方式
本文講述的是Android中RelativeLayout、FrameLayout的用法。具體如下:RelativeLayout是一個按照相對位置排列的布局,跟Absolu
1、為什麼要使用屬性動畫?Google在3.0以後推出了屬性動畫,之所以會出屬性動畫,是因為傳統動畫在對象交互方面存在缺陷。可以通過一個很經典的例子來發現屬性動畫和傳統動