上一篇講了Android觸摸事件的傳遞機制,具體可以看這裡 初識Android觸摸事件傳遞機制。既然知道Android中觸摸事件的傳遞分發,那麼它能解決什麼樣的問題,在我們實際開發中如何應用,這點很重要,知道原理是為了解決問題而準備的。這篇文章的核心講的如何解決View的滑動沖突,這個問題在日常開發中很常見,比如内部嵌套Fragment視圖是左右滑動,外部用一個ScrollView來包含,可以上下滑動,如果不進行滑動沖突處理的話,就會造成外部滑動方向和内部滑動方向不一緻。
常見的滑動沖突場景
滑動沖突的處理規則
外部攔截法
内部攔截法
小結
常見的滑動沖突場景可以簡單分為以下三種:
場景1:外部滑動方向和内部滑動方向不一緻
場景2:外部滑動方向和内部滑動方向一緻
場景3:上面兩種情況的嵌套
如圖:

場景1,主要是将ViewPager和Fragment配合使用所組成的頁面滑動效果,主流應用幾乎都會使用這個效果。在這個效果中可以通過左右滑動來切換頁面,而每個頁面内部往往又是一個ListView,是以就造成了滑動沖突,但是在ViewPager内部處理了這種滑動沖突,是以在采用ViewPager時我們就無須關注這個問題,而如果把ViewPager換成ScrollView,那就必須自己手動處理,不然造成的結果就是内外兩層隻能一層能夠滑動。
場景2,就複雜一點,當内外兩層都在同一個方向可以滑動的時候,顯然存在邏輯問題。因為當手指開始滑動的時候,系統無法知道使用者到底是想讓哪一層滑動,是以當手指滑動的時候就會出現問題,要麼隻有一層滑動,要麼就是内外兩層都滑動但很卡頓。
場景3,是場景1和場景2兩種情況的嵌套,顯得更複雜了。比如外部有一個SlideMenu效果,内部有一個ViewPager,ViewPager的每一個頁面中又是一個ListView。雖然場景3滑動沖突看起來很複雜,但都是幾個單一的滑動沖突的疊加,是以需要一一拆解開來即可。
一般來說,不管滑動沖突有多麼複雜,它都有既定的規則,根據這些規則我們就可以選擇合适的方法去處理。
對于場景1,它的處理規則就是:當使用者左右滑動時,需要讓外部的View攔截點選事件,當使用者上下滑動,需要讓内部View攔截點選事件。具體來說就是根據滑動是水準滑動還是豎直滑動來判斷到底是由誰來攔截事件。
簡單來說,就是根據水準方向和豎直方向的距離差來判斷,如果是Dx>Dy,那麼則是水準滑動,如果是Dy>Dx,那麼則是豎直滑動。
場景2,則是比較特殊,它無法根據滑動的角度,距離差以及速度差來做判斷。這個時候就需要從業務上找到突破點,比如,當處于某種狀态時需要外部View響應使用者的滑動,而處于另外一種狀态時需要内部View來響應View的滑動
對于場景3的話,它的滑動規則也更複雜,和場景2一樣,同樣是從業務上找到突破點。
外部攔截法是指點選事件都是先經過父容器的攔截處理,如果父容器需要此事件就攔截,如果不需要此事件,就不攔截了,這樣就可以解決滑動沖突的問題,外部攔截法需要重寫父容器的onInterceptTouchEvent方法,在内部做相應的攔截即可,僞代碼如下:
首先ACTION_DOWN這個事件,父容器必須傳回false,這樣保證後續move和up的事件可以傳遞給子View,根據move事件來決定是否攔截,如果父容器攔截就傳回true,否則傳回false。
實作一個自定義類似ViewPager的控件,嵌套ListView的效果,源代碼如下:
這個情況的攔截條件就是父容器在滑動過程中水準距離差比垂直距離差大,那麼就進行攔截,否則就不攔截,繼續傳遞事件。
内部攔截法是指父容器不攔截任何事件,所有的事件都傳遞給子元素,如果子元素需要此事件就直接消耗掉,否則就交給父容器進行處理,這種方法和Android中的事件分發機制不一緻,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,使用起來較外部攔截法複雜。僞代碼如下:
當子元素調用requestDisallowInterceptTouchEvent(false)方法時,父元素才能繼續攔截所需的事件。
前面是用自定義類似的ViewPager,現在重寫一個ListView,我們可以自定義一個ListView,叫做ListViewEx,然後對内部攔截法的模闆代碼進行修改即可。
同時對于包含ListViewEx外部布局進行修改,在onInterceptTouchEvent事件上不進行攔截
這個攔截規則也是父容器在滑動過程中水準距離差與垂直距離差相比。
總的來說,滑動沖突的場景可以分為三種,内外部方向不一緻、内外部方向一緻、嵌套前面兩種情況。如何解決,不管多麼複雜的滑動沖突,可以進行拆分,根據的一定的規則,第一種情況可根據滑動距離差、速度差和角度差來解決,第二種和第三種情況,可根據業務上找到突破點,業務上一種狀态需要響應,切換到另外一種狀态時則不響應,根據業務需求得出相應的處理規則,有了處理規則可以進行下一步處理。
源于對掌握的Android開發基礎點進行整理,羅列下已經總結的文章,從中可以看到技術積累的過程。
1,Android系統簡介
2,ProGuard代碼混淆
3,講講Handler+Looper+MessageQueue關系
4,Android圖檔加載庫了解
5,談談Android運作時權限了解
6,EventBus初了解
7,Android 常見工具類
8,對于Fragment的一些了解
9,Android 四大元件之 " Activity "
10,Android 四大元件之" Service "
11,Android 四大元件之“ BroadcastReceiver "
12,Android 四大元件之" ContentProvider "
13,講講 Android 事件攔截機制
14,Android 動畫的了解
15,Android 生命周期和啟動模式
16,Android IPC 機制
17,View 的事件體系
18,View 的工作原理
19,了解 Window 和 WindowManager
20,Activity 啟動過程分析
21,Service 啟動過程分析
22,Android 性能優化
23,Android 消息機制
24,Android Bitmap相關
25,Android 線程和線程池
26,Android 中的 Drawable 和動畫
27,RecylerView 中的裝飾者模式
28,Android 觸摸事件機制
29,Android 事件機制應用
30,Cordova 架構的一些了解
31,有關 Android 插件化思考
32,開發人員必備技能——單元測試