1. 程式人生 > >Android自定義View之事件分發機制總結

Android自定義View之事件分發機制總結

事件序列

(1)手指接觸屏幕後會產生一系列事件,事件分為3種:ACTION_DOWN(手指剛剛接觸螢幕)、ACTION_MOVE(手指在螢幕移動)、ACTION_UP(手指從螢幕鬆開)

(2)一個事件序列為ACTION_DOWN-->ACTION_MOVE-->...-->ACTION_UP 

事件傳遞的順序

Activity-->Window-->decor view-->我們的layout,ViewGroup-->我們佈局中被點選的子View

如果我們的子View沒有處理事件,那事件就會反向向上傳遞回來:

我們佈局中被點選的子View-->上層的ViewGroup-->decor view-->Window-->Activity

如果所有的View都沒有消耗事件,那最後事件會傳回到Activity,由Activity處理(Activity的onTouchEvent()方法被呼叫)
三大方法

ViewGroup中有3個跟事件分發有關的方法,分別是 dispatchTouchEvent、 onInterceptTouchEvent、onTouchEvent。

(1)dispatchTouchEvent方法

dispatchTouchEvent方法用來進行事件的分發。事件傳遞到當前View時,這個方法就會被呼叫。dispatchTouchEvent方法裡面包含了具體的事件分發邏輯,返回結果受當前View的onTouchEvent方法和下級View的dispatchTouchEvent方法的影響。

(2)onInterceptTouchEvent方法

onInterceptTouchEvent方法在dispatchTouchEvent方法內部被呼叫,用來判斷是否攔截某個事件。如果當前View攔截了某個事件,那麼在同一個事件序列當中,此方法不會被再次呼叫,返回結果表示是否攔截當前事件。這個方法只有VewGroup中有,View中沒有。

(3)onTouchEvent方法

在dispatchTouchEvent方法中呼叫,用來處理點選事件,返回結果表示是否消耗當前事件,如果不消耗,則在同一個事件序列中,當前View無法再次接收到事件。

onTouchListener、onTouchEvent、onClickListener的優先順序

(1)onTouchListener和onTouchEvent都在dispatchTouchEvent方法中被呼叫,onClickListener在onTouchEvent方法中被呼叫

(2)onTouchListener的優先順序高於onTouchEvent方法,如果onTouchListener的onTouch方法返回true,則onTouchEvent方法不會被呼叫,當然onClickListener就更不會被呼叫了

(3)在onTouchEvent方法中,如果當前View設定了onClickListener,那麼onClickListener的onClick方法會被呼叫

(4)只要View的CLICKABLE和LONKG_CLICKABLE有一個為true,View就會消耗當前事件,也就是說onTouchEvent方法最後會返回true。

(5)View的LONG_CLICKABLE屬性預設為false,而CLICKABLE屬性和具體的View有關,可點選的View的CLICKABLE屬性為true,不可點選的View的CLICKABLE屬性為false。

ViewGroup中的事件分發邏輯

ViewGroup中的事件分發邏輯可以用一段虛擬碼來表述

public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
consume = onTouchEvent();
}else {
consume = child.dispatchTouchEvent(ev);
}

return consume;

}
從上述的虛擬碼中我們可以總結出ViewGroup中的事件分發流程:

(1)事件傳遞到ViewGroup時,dispatchTouchEvent方法會被呼叫。如果這個ViewGroup的onInterceptTouchEvent方法返回true,則表示它要攔截事件,事件就會交給當前ViewGroup的onTouchEvent方法處理。

(2)如果當前ViewGroup的onInterceptTouchEvent返回false,即不攔截事件,則會呼叫子元素的dispatchTouchEvent方法,這樣就把事件傳遞給了子元素。

(3)如果子元素沒有消耗事件,也就是子元素的dispatchTouchEvent方法返回false,那事件會由當前ViewGroup自己處理,當前ViewGroup的onTouchEvent會被呼叫。如果當前ViewGroup的dispatchTouchEvent方法也返回false,最後就會一層層往上,如果事件一直沒有被消耗,那麼最後Activity的onTouchEvent方法會被呼叫

(4)這裡需要理解一下的是ViewGroup繼承自View,ViewGroup中並沒有onTouchEvent方法。在所有子元素沒有消耗事件時,ViewGroup會呼叫父類,也就是View的dispatchTouchEvent方法,從而呼叫到onTouchEvent方法來自己處理事件,如果自己沒有消耗事件,dispatchTouchEvent方法就會返回false,從而將事件反向往上層傳遞。

(5)如果ACTION_DOWN事件子元素沒處理(onTouchEvent返回false),那這個事件序列的其他事件(MOVE和UP事件)都不會再分派給子元素處理。

(6)ViewGroup預設不攔截任何事件

(7)對於ACTION_DOWN事件,ViewGroup每次都會呼叫onInterceptTouchEvent方法來判斷是否需要攔截事件,一旦確定要攔截事件,後續的ACTION_MOVE和ACTION_UP事件都ViewGroup自己處理,不會傳遞給子View,也不會再呼叫onInterceptTouchEvent方法。所以onInterceptTouchEvent方法不是每次事件都會被呼叫的。

(8)子View可以通過requestDisallowInterceptTouchEvent方法來干預父元素的除了ACTION_DOWN意外的事件分發過程

View中的事件分發邏輯

requestDisallowInterceptTouchEvent方法

requestDisallowInterceptTouchEvent方法用於影響父元素的事件攔截策略,requestDisallowInterceptTouchEvent(true),表示不允許父元素攔截事件,這樣事件就會傳遞給子View。一般這個方法子View用的多,可以用來處理滑動衝突問題。

事件分發邏輯

(1)View中沒有onInterceptTouchEvent方法,所以一旦事件傳遞到View,那麼View的dispatchTouchEvent方法就會被呼叫。

(2)dispatchTouchEvent方法中處理事件的邏輯順序是onTouchListener–>onTouchEvent–>onClickListener。

(3)也就是說如果View設定了onTouchListener,那onTouchListener的onTouch方法會被呼叫,如果onTouch方法返回true,那事件就被消耗了,事件分發結束,onTouchEvent不會被呼叫。

(4)如果onTouch方法返回false,那麼onTouchEvent就會被呼叫。如果View設定了onClickListener,當ACTION_UP事件到來時,onTouchEvent中的onClickListener的onClick方法也會被呼叫。

(5)View一般都會消耗事件,如果View沒有消耗ACTION_DOWN事件,那後面ACTION_MOVE和ACTION_UP就都不會傳遞給View。

常用的滑動衝突處理邏輯

(1)利用父佈局的onInterceptTouchEvent方法

這個思路就是在父佈局需要處理事件時攔截下來,其他時候不攔截。有幾個注意點:

對於ACTION_DOWN事件,onInterceptTouchEvent方法必須返回false,因為一旦返回true,子元素永遠也接收不到事件了,那還解決個毛線衝突。
主要的邏輯就在ACTION_MOVE的處理上,需不需要攔截的邏輯在這裡根據需要來實現
對於ACTION_UP事件返回false,因為一旦父元素返回true,那子View就接受不到ACTION_UP事件了,也就無法觸發onClick事件。
(2)利用子View的requestDisallowInterceptTouchEvent方法

這個思路就是父佈局預設攔截除了ACTION_DOWN的所有事件,子View中在dispatchTouchEvent方法中根據需要來干預父佈局的攔截策略。預設不允許父佈局攔截事件,在需要父佈局處理事件時,通過requestDisallowInterceptTouchEvent(false)方法讓父佈局處理事件,其他時候都由子View處理。

注意點:

同樣的對於ACTION_DOWN事件,onInterceptTouchEvent方法必須返回false,其他事件預設返回true
在子View的dispatchTouchEvent方法中,對於ACTION_DOWN事件,通過呼叫requestDisallowInterceptTouchEvent(true)預設不允許父佈局攔截事件,這樣後續事件都交給子View處理
在子View的dispatchTouchEvent方法中,對於ACTION_MOVE事件,預設是子View處理,在需要父佈局處理時,呼叫requestDisallowInterceptTouchEvent(false)方法來讓父佈局攔截事件,交給父佈局處理。

相關推薦

Android定義View事件分發機制總結

事件序列 (1)手指接觸屏幕後會產生一系列事件,事件分為3種:ACTION_DOWN(手指剛剛接觸螢幕)、ACTION_MOVE(手指在螢幕移動)、ACTION_UP(手指從螢幕鬆開) (2)一個事件序列為ACTION_DOWN-->ACTION_MOV

Android定義View分貝儀

一、說明        最近在整理自定義View方面的知識,偶爾看到meizu工具箱的分貝儀效果,感覺它的實效效果還挺好的,遂想自己模擬實現練練手,廢話不多說,直接開擼。 二、效果圖 首先看一下效果圖: 看效果還挺炫酷

Android定義ViewCanvas

https://www.jianshu.com/p/fb18c28d6627 用繼承View的方式來自定義View,我們就需要重寫onDraw方法,也就是得咱自己來畫圖了。畫圖就得用到畫筆和畫布,也就是Paint和Canvas。我們來了解下Canvas。 Canvas Canvas我們可

Android 定義ViewCanvas詳解

自定義View的相關文章: Android 實現一個簡單的自定義View Android 自定義View步驟 Android Paint詳解 Android 自定義View之Canvas相關方法說明 Android 自定義View例項之 “京東跑”

Android : 定義View流式佈局

寫了一個很簡單的佈局 這是周圍圓框的drawable <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android">

android定義View仿通訊錄側邊欄滑動,實現A-Z字母檢索

我們的手機通訊錄一般都有這樣的效果,如下圖: OK,這種效果大家都見得多了,基本上所有的android手機通訊錄都有這樣的效果。那我們今天就來看看這個效果該怎麼實現。 一.概述 1.頁面功能分析 整體上來說,左邊是一個ListView,右邊是一個自定義View,但

Android定義ViewgetTextBounds()

在Android自定義View的過程中一定會用到Paint,而paint屬性中有一個方法getTextBounds(String text,int start,int end,Rext bounds),它的中文解釋是:返回一個包含中文的矩形邊界,位置為(start,end) 英文解釋:Retur

Android定義View定義屬性

在Android開發中經常會用到自定義View的情況,而在自定義View時,自定義屬性是必須用到的。 1、新建一個自定義View如CustomView 它的自定義屬性主要是通過declare-styleable標籤為其配置自定義屬性。具體做法是:在res/values/目錄下增加一個reso

Android -- 定義viewStepView

先看看實現的效果: 2,首先我們來看看我們常規的自定義view的基礎步驟吧         1,繼承View,重寫構造方法 2,自定義屬性 3,重寫onMeasure()測量控制元件高度 4,重寫onDra

Android 定義View 可隨意拖動的View

因為趕專案本人停更兩個月 從今天開始又可以更新了 今天說一下這個可隨意拖動的view 簡單說一下這個view效果 和 發展 一開始這種效果是使用在網頁端的特別是購物類 例如某寶 某東 購物車和客服視窗 都有使用這個懸浮可拖動的設計效果 後來才發展到的移動端 還有

Android 定義View咖啡動畫

文章目錄效果畫杯子畫杯墊畫煙霧 效果 大概思路 自定義view,直接繼承view 複寫onSizeChanged()方法,在此計算杯墊,杯子,煙霧效果的path 在onDraw()方法中,描繪杯墊,杯子 處理煙霧動畫效果 畫杯子 這裡需要畫兩部分內容,第

Android 定義View下雨動畫

文章目錄效果思路畫雲畫雨滴優化 效果 開始前先做個熱身( ˘•灬•˘ ) 自己實現比較容易,但是到了要出部落格整理思路,總結要點的時候就撓頭,不知雲所以,所以最簡單的還是 如果對安卓UI有興趣的朋友可以加我好友互相探討, 思路 思路比較簡單,整個view無

android定義View定義EditText(新增刪除功能)

           忙忙碌碌20天,新的專案終於接近尾聲了。今天公司召集幾個使用者體驗師和美工一起吐糟這20天做的這個新產品,對於產品提出了很多建議,這幾天就改介面了。在這個專案中大量的使用了EditText元件,並且添加了刪除功能。這裡面都是用RelativeLayou

android定義view畫圓隨著手指移動

public class MyView extends View { private Paint mFanPaint,mTextPaint;//扇形畫筆和文字畫筆 public float AxisX=100; public float AxisY=100; public MyView(

Android定義view實現帶checkbox的Snackbar

前言 最近專案要求實現一個類似於snackbar功能,但是又不完全是snackbar的外掛,本來想在Google提供的snackbar裡面進行更改,但是這樣太麻煩了,於是自己動手實現了一個snackbar。先看下效果圖: 1.要解決的問題 1.彈框裡面除了文字提示之外還有一個按鈕,這個按

android定義View3D索引效果

效果圖: 我的小霸王太卡了。 最近工作比較忙,今天搞了一下午才搞出來這個效果,這種效果有很多種實現方式,最常見的應該是用貝塞爾曲線實現的。今天我們來看另一種不同的實現方式,只需要用到 canvas.scale(),有沒有很好奇是怎麼實現的呢。 首先來說一下思路,只要有了思

android 定義view側滑效果

效果圖: 看網上的都是兩個view拼接,預設右側的不顯示,水平移動的時候把右側的view顯示出來。但是看最新版QQ上的效果不是這樣的,但給人的感覺卻很好,所以獻醜來一發比較高仿的。 知識點: 1、ViewDragHelper 的用法; 2、滑動衝突的解決; 3、自定

android 定義view選座功能

效果圖: 介面比較粗糙,主要看原理。 這個介面主要包括以下幾部分 1、座位 2、左邊的排數 3、左上方的縮圖 4、縮圖中的紅色區域 5、手指移動時跟隨移動 6、兩個手指縮放時跟隨縮放 主要技術點 1、矩陣Matrix 2、GestureDetector與S

Android定義View實現簡單炫酷的球體進度球

前言 最近一直在研究自定義view,正好專案中有一個根據下載進度來實現球體進度的需求,所以自己寫了個進度球,程式碼非常簡單。先看下效果: 效果還是非常不錯的。 準備知識 要實現上面的效果我們只要掌握兩個知識點就好了,一個是Handler機制,用於發訊息重新整理我們的進度球,一個是clip

從零開始學Android定義View動畫系列——屬性動畫(3)

屬性動畫對補間動畫進行了很大幅度的改進,之前補間動畫可以做到的屬性動畫也能做到,補間動畫做不到的現在屬性動畫也可以做到了。因此,今天我們就來學習一下屬性動畫的高階用法,看看如何實現一些補間動畫所無法實現的功能。 ValueAnimator的高階用法 補間