天天看點

View的事件體系

View雖然不屬于四大元件,但它的作用堪比四大元件,甚至比Receiver和Provider的重要性都大,在Android開發中,Activity承擔這可視化的功能,同時Android系統提供了很多基礎控件,常見的有Button、Textview、CheckBox等。

什麼是View

View是一種界面層的控件的一種抽象,它代表了一個控件。除了View,還有ViewGroup,ViewGroup内部包含了許多個控件,即一組View,在ViewGroup也繼承了View,這就意味着View本身就可以是單個控件也可以是由多個控件組成的一組控件,通過這種關系形成了View樹的結構。

View的事件體系

View的位置參數

View的位置主要由它的四個頂點來決定,分别對應于View的四個屬性:top、left、right、bottom,其中top是左上角縱坐标,left是左上角橫坐标,right是右下角橫坐标,bottom是右下角的縱坐标。需要注意的是,這些坐标都是相對于View的父容器來說的,因為它是一種相對坐标。

View的事件體系

在Android中,X軸和Y軸的正方向分别為右和下。那麼就可以得出以下關系:

MotionEvent和TouchSlop

在手指接觸螢幕後會産生一系列的事件,典型的事件類型有如下幾種:

ACTION_DOWN——手指剛接觸螢幕

ACTION_MOVE——手指在螢幕上移動

ACTION_UP——手指從螢幕上松開的一瞬間

正常情況下,一次手指觸摸螢幕的行為會觸發一系列點選事件,如下:

點選螢幕後離開松開,事件序列為DOWN->UP

點選螢幕滑動一會再松開,事件序列為DOWN->MOVE->.......->MOVE->UP

同時我們可以通過MotionEvent對象我們可以得到點選事件發生的X坐标和Y坐标。為此,系統提供了兩組方法:getX/getY和getRawX/getRawY,差別很簡單,前者傳回的是相對于目前View左上角的X和Y坐标,而後者傳回的相對于手機螢幕左上角的X和Y坐标。

TouchSlop是系統所能識别出的被認為是滑動的最小距離,換句話說,當手指在螢幕上滑動時,如果兩次滑動之間的距離小于這個常量,那麼系統就不認為你是在進行滑動操作,因為滑動的距離太短了,系統就不認為它是滑動,這是一個常量,跟裝置有關。可以通過以下方式擷取:

在Android裝置中,滑動幾乎是應用的标配,不管是下拉重新整理還是SlidingMenu,它們的基礎都是滑動。是以,掌握滑動的方法是實作絢麗的自定義控件的基礎,有三種方式實作View的滑動:

scrollTo/scrollBy方法來實作

使用動畫

改變布局參數

首先,我們需要擷取View裡的兩個屬性mScrollX和mScrollY,在滑動過程中,mScrollX的值總是等于View的左邊緣和View内容左邊緣在水準方向的距離,而mScrollY的值總等于View上邊緣和View内容上邊緣在豎直方向的距離。View邊緣是指View的位置,由四個頂點組成,而View内容邊緣是指View中的内容的邊緣,scrollTo/scrollBy隻能改變View内容的位置而不能改變View在布局中的位置。

如果從左往右滑動,那麼mScrollX為負值,反之為正值,如果從上往下滑動,那麼mScrollY為負值,反之為正值。

View的事件體系

使用動畫我們能夠讓一個View進行平移,而平移就是一個滑動。比如:

但是動畫移動會有個問題,那就是View動畫并不能真正改變View的位置,這會帶來一個很嚴重的問題,就是移動到新位置了,卻發現無法觸發事件,而單擊原來的位置卻能觸發。那麼從Android3.0開始,使用屬性動畫可以解決上面問題。

改變布局參數,即改變LayoutParams,這個比較好了解,比如我們想把一個Button向右平移100px,我們隻需要将這個Button的LayoutParams裡的marginLeft參數的值增加100px即可。

三種滑動方式對比:

scrollTo/scrollBy:操作簡單,适合對View内容的滑動

動畫:操作簡單,主要使用于沒有互動的View和實作複雜的動畫效果

改變布局參數:操作稍微複雜,适用于有互動的View

知道了View的滑動,我們還需要知道如何實作View的彈性滑動,比較生硬的滑過去,這種方式的使用者體驗實在太差了,是以我們要實作漸近式滑動。如何實作彈性滑動呢,有個共同思想:将一次大的滑動分成若幹次小的滑動,并在一個時間段内完成,常見的彈性滑動具體實作方式有很多,比如通過Scroller、Handler#postDelayed,以及Thread#Sleep等等。

點選事件的傳遞規則

點選事件的分發過程由三個很重要的方法共同完成:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。

dispatchTouchEvent(MotionEvent ev),用來進行事件的分發。

onInterceptTouchEvent(MotionEvent event),用來判斷是否攔截某個事件,如果目前View攔截了某個事件,那麼在同一個事件序列中,此方法不會被再次調用,傳回結果表示是否攔截目前事件。

onTouchEvent(MotionEvent event),在dispatchTouchEvent方法調用,用來處理目前點選事件,傳回結果表示是否消耗目前事件。如果不消耗,那麼在同一個事件序列中,目前View無法再次接收到事件。

簡單來說,對于一個根ViewGroup來說,點選事件産生後,首先會傳遞給它,這時它的dispatchTouchEvent會被調用,如果這個ViewGroup的onInterceptTouchEvent方法傳回true就表示它要攔截目前事件,接着事件就會交給這個ViewGroup處理,即它的onTouchEvent方法就會被調用,如果這個ViewGroup的onInterceptTouchEvent方法傳回false,就表示它不攔截目前事件,這時目前事件就會繼續傳遞給它的子元素,接着子元素的dispatchTouchEvent方法就會被調用,如此反複直到事件被最終處理。

還有一個當View需要處理事件時,如果它設定了OnTouchListener,那麼OnTouchListener中的onTouch方法會被回調,OnTouchListener優先于onTouchEvent。在onTouchEvent中,如果設定了OnClickListener,那麼它的OnClick方法會被調用,可以看出我們平時常用的OnClickListener優先級最低,onTouch>onClick.

View不處理流程:

View的事件體系

View處理流程

View的事件體系

一些總結:

同一個事件序列是指從手指接觸螢幕的那一刻起,到手指離開螢幕的那一刻結束。一般是以down事件開始,中間含有數量不定的move事件,最終以up事件結束。

正常情況下,一個事件序列隻能被一個View攔截且消耗。

某個View一旦決定攔截,那麼這個事件序列就隻能由它來處理,那麼同一事件序列中的其他事件都不會再交給它來處理,并且事件将重新交給它的父元素去處理,即父元素的onTouchEvent會被調用。

如果View不消耗除ACTION_DOWN以外的其他事件,那麼這個點選事件就會消失,此時父元素的onTouchEvent并不會被調用,最終會交給Activity處理。

ViewGroup預設不攔截任何事件。

View中沒有onInterceptTouchEvent方法。

View的onTouchEvent預設都會被消耗,除非它是不可點選的。

事件傳遞過程是由外向内的,即事件先是傳遞給父元素,然後再由父元素分發給子View。

常見的滑動沖突場景

View的事件體系

場景1:主要是講ViewPager和Fragment配合使用組成的頁面滑動效果,會産生的問題。

場景2:在開發中,内外兩層同時能上下滑動或者内外兩層同時能左右滑動。

場景3:是場景1和場景2兩種情況的嵌套。

如何處理

根據滑動是水準滑動還是豎直滑動來判斷到底是由誰來攔截事件。幾種處理方式:

外部攔截法。點選事情都是先經過父容器的攔截處理,如果父容器需要次事件就攔截,如果不需要此事件就不攔截,這樣就可以解決滑動沖突的問題。

内部攔截法。父容器不攔截任何事件,所有的事件都傳遞給子元素,如果子元素需要此事件就直接消耗點,否則就交由父容器進行處理。

源于對掌握的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,開發人員必備技能——單元測試