欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 事件分發(fā)詳解及示例代碼

 更新時間:2016年08月26日 15:24:57   作者:Idtk  
本文主要介紹Android 事件分發(fā),這里整理詳細(xì)的資料及簡單的示例來講解Android事件分發(fā)的知識,有需要的小伙伴可以參考下

事件分發(fā)是Android中非常重要的機(jī)制,是用戶與界面交互的基礎(chǔ)。這篇文章將通過示例打印出的Log,繪制出事件分發(fā)的流程圖,讓大家更容易的去理解Android的事件分發(fā)機(jī)制。

一、必要的基礎(chǔ)知識

1、相關(guān)方法

Android中與事件分發(fā)相關(guān)的方法主要包括dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三個方法,而事件分發(fā)一般會經(jīng)過三種容器,分別為Activity、ViewGroup、View。下表對這三種容器分別擁有的事件分發(fā)相關(guān)方法進(jìn)行了整理。

事件相關(guān)方法 方法功能 Activity ViewGroup View
public boolean dispatchTouchEvent 事件分發(fā) Yes Yes Yes
public boolean onInterceptTouchEvent 事件攔截 No Yes No
public boolean onTouchEvent 事件消費(fèi) Yes Yes Yes

分發(fā): dispatchTouchEvent如果返回true,則表示在當(dāng)前View或者其子View(子子…View)中,找到了處理事件的View;反之,則表示沒有尋找到

攔截: onInterceptTouchEvent如果返回true,則表示這個事件由當(dāng)前View進(jìn)行處理,不管處理結(jié)果如何,都不會再向子View傳遞這個事件;反之,則表示當(dāng)前View不主動處理這個事件,除非他的子View返回的事件分發(fā)結(jié)果為false

消費(fèi): onTouchEvent如果返回true,則表示當(dāng)前View就是事件傳遞的終點(diǎn);反之,則表示當(dāng)前View不是事件傳遞的終點(diǎn)

2、相關(guān)事件

這篇文章中我們只考慮4種觸摸事件: ACTION_DOWN、ACTION_UP、ACTION_MOVE、ACTION_CANAL。 事件序列:一個事件序列是指從手指觸摸屏幕開始,到手指離開屏幕結(jié)束,這個過程中產(chǎn)生的一系列事件。一個事件序列以ACTION_DOWN事件開始,中間可能經(jīng)過若干個MOVE,以ACTION_UP事件結(jié)束。 接下來我們將使用之前的文章自定義View——彈性滑動中例子來作為本文的示例,簡單增加一些代碼即可,修改之后的代碼請點(diǎn)擊查看。

二、示例的默認(rèn)情況

我們可以從示例代碼的xml中看出,圖片都是可點(diǎn)擊的。

<?xml version="1.0" encoding="utf-8"?>
<com.idtk.customscroll.ParentView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:padding="10dp"
  tools:context="com.idtk.customscroll.MainActivity"
  >

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/zhiqinchun"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/hanzhan"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/shengui"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/dayu"
    android:clickable="true"/>

</com.idtk.customscroll.ParentView>

我們現(xiàn)在來點(diǎn)擊一下,查看下打印出的日志。

 

根據(jù)打印出的log來繪制一張事件傳遞的流程圖

 

現(xiàn)在來理一下事件序列的流程:

  1. ACTION_DOWN事件從Activity#dispatchTouchEvent方法開始
  2. ACTION_DOWN事件傳遞至ViewGroup#dispatchTouchEvent方法,ViewGroup#onInterceptTouchEvent返回false,表示不攔截ACTION_DOWN
  3. ACTION_DOWN事件傳遞到View#dispatchTouchEvent方法,在View#onTouchEvent進(jìn)行執(zhí)行,返回true,表示事件已經(jīng)被消費(fèi)
  4. 返回的結(jié)果true,被回傳到View#dispatchTouchEvent,之后回傳到ACTION_DOWN事件的起點(diǎn)Activity#dispatchTouchEvent方法
  5. ACTION_UP事件的傳遞過程與ACTION_DOWN相同,這里不再復(fù)述

這里使用工作中的情況來模擬一下:老板(Activity)、項(xiàng)目經(jīng)理(ViewGroup)、軟件工程師(View)

老板分配一個任務(wù)給項(xiàng)目經(jīng)理(Activity#dispatchTouchEvent → ViewGroup#dispatchTouchEvent),項(xiàng)目經(jīng)理選擇自己不做這個任務(wù)(ViewGroup#dispatchTouchEvent返回false),交由軟件工程師處理這個任務(wù)(<View#dispatchTouchEvent)(我們忽略總監(jiān)與組長的情況),軟件工程師完成了這個任務(wù)(View#onTouchEvent返回true)

把結(jié)果告訴項(xiàng)目經(jīng)理(返回結(jié)果true,View#dispatchTouchEvent→ ViewGroup#dispatchTouchEvent),項(xiàng)目經(jīng)理把結(jié)果告訴老板(返回結(jié)果true,ViewGroup#dispatchTouchEvent→Activity#dispatchTouchEvent)

項(xiàng)目經(jīng)理完成的不錯,老板決定把這個項(xiàng)目的二期、三期等都交給項(xiàng)目經(jīng)理,同樣項(xiàng)目經(jīng)理也覺得這個軟件工程師完成的不錯,所以也把二期、三期等都交給這個工程師來做
通過上面的傳遞過程,我們可以得出一些結(jié)論:

  1. 某個ViewGroup如果onInterceptTouchEvent返回為false,則表示ViewGroup不攔截事件,而是將其傳遞給View#dispatchTouchEvent方法
  2. 事件總是由父元素分發(fā)給子元素
  3. 某個View如果onTouchEvent返回true,表示事件被消費(fèi),則其結(jié)果將直接通過dispatchTouchEvent方法傳遞回Activity
  4. 如果某個View消費(fèi)了ACTION_DOWN事件,那么這個事件序列中的后續(xù)事件也將交由其進(jìn)行處理(有一些特殊情況除外,比如在序列中的之后事件進(jìn)行攔截)

三、在View中不消費(fèi)事件

我們現(xiàn)在修改示例代碼的xml部分,android:clickable="true"全部修改為android:clickable="false"

<?xml version="1.0" encoding="utf-8"?>
<com.idtk.customscroll.ParentView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:padding="10dp"
  tools:context="com.idtk.customscroll.MainActivity"
  >

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/zhiqinchun"
    android:clickable="false"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/hanzhan"
    android:clickable="false"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/shengui"
    android:clickable="false"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/dayu"
    android:clickable="false"/>

</com.idtk.customscroll.ParentView>

這時再點(diǎn)擊一下,查看新打印出的日志

 

現(xiàn)在根據(jù)log中顯示的邏輯,分別繪制ACTION_DOWN事件與ACTION_UP事件傳遞的流程圖

 

 

我們來整理下這個事件序列的流程:

  1. ACTION_DOWN事件的傳遞與之前相同,不同的地方在于,返回值的傳遞
  2. 因?yàn)椴豢牲c(diǎn)擊,View#onTouchEvent返回值為false,將其傳遞給自己的dispatchTouchEvent方法,之后傳遞到ViewGroup#dispatchTouchEvent方法,再傳遞到ViewGroup#onTouchEvent方法
  3. ViewGroup返回false之后,ACTION_DOWN事件交由Activity#onTouchEvent方法進(jìn)行處理,然而依舊返回false,最后ACTION_DOWN事件的返回結(jié)果即為false
  4. ACTION_UP事件在發(fā)現(xiàn)View、ViewGroup并不處理ACTION_DOWN事件后,直接將其傳遞給了Activity#onTouch方法處理,處理返回false,ACTION_UP事件的返回結(jié)果即為false

這里使用工作中的情況來模擬:依舊是老板(Activity)、項(xiàng)目經(jīng)理(ViewGroup)、軟件工程師(View) 從老板交任務(wù)給項(xiàng)目經(jīng)理,項(xiàng)目經(jīng)理交任務(wù)給工程師,這一段流程和之前的例子相同。不同之處是軟件工程師沒有完成這個任務(wù)(View#onTouchEvent返回false),告訴項(xiàng)目經(jīng)理我沒有完成,然后項(xiàng)目經(jīng)理自己進(jìn)行了嘗試,同樣沒有完成(ViewGroup#onTouchEvent返回false),項(xiàng)目經(jīng)理告訴了老板,我沒有完成,然后老板自己試了下也沒有完成這個任務(wù)(Activity#onTouchEvent返回false),但之后的也有項(xiàng)目的二期、三期,不過老板知道你們完成不了,所以都是他自己進(jìn)行嘗試,不過很慘都沒完成。(這段有點(diǎn)與正常情況不同,不過只是打個比方)

通過結(jié)合上面兩個例子,可以得出一些結(jié)論:

  1. 某個View如果onTouchEvent返回false,表示事件沒有被消費(fèi),則事件將傳遞給其父View的onTouchEvent進(jìn)行處理
  2. 某個View如果它不消耗ACTION_DOWN事件,那么這個序列的后續(xù)事件也不會再交由它來處理
  3. 如果事件沒有View對其進(jìn)行處理,那么最后將有Activity進(jìn)行處理
  4. View默認(rèn)的onTouchEvent在View可點(diǎn)擊的情況下,將會消耗事件,返回true;不可點(diǎn)擊的情況下,則不消耗事件,返回false(longClickable的情況,讀者可以自行測試,結(jié)果與clickable相同)

四、在ViewGroup中攔截事件

事件分發(fā)中攔截的情況,這里我把它分為2種,一種是在ACTION_DOWN事件時,就進(jìn)行攔截的;另一種是在ACTION_DOWN之后的事件序列中,對事件進(jìn)行了攔截。

1、在事件開始時攔截

為了達(dá)到在ViewGroup中,一開始就攔截觸摸事件的效果,我們需要進(jìn)行修改,在ParentView#onInterceptTouchEvent方法的最后部分,我注釋掉的intercept=true;進(jìn)行恢復(fù),然后為activity_main.xml中的ParentView增加android:clickable="true"屬性。

<?xml version="1.0" encoding="utf-8"?>
<com.idtk.customscroll.ParentView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:padding="10dp"
  tools:context="com.idtk.customscroll.MainActivity"
  >

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/zhiqinchun"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/hanzhan"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/shengui"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/dayu"
    android:clickable="true"/>

</com.idtk.customscroll.ParentView>

 

我們現(xiàn)在來看下攔截情況下的事件流程圖

 

 

這里大部分和之前的例子相同,主要的區(qū)別是在于ViewGroup#onInterceptTouchEvent方法中,對傳遞的事件進(jìn)行了攔截,返回true,ACTION_DOWN事件就傳遞到了ViewGroup#onTouchEvent中進(jìn)行處理,ACTION_DOWN事件之后的傳遞就與之前的例子相同了。另一點(diǎn)重要的區(qū)別是,在ViewGroup攔截下事件之后,此事件序列的其余事件,在進(jìn)入ViewGroup#dispatchTouchEvent方法之后,不在需要進(jìn)行是否攔截事件的判斷,而是直接進(jìn)入了onTouchEvent方法之中。

使用工作中的情況來模擬:老板(Activity)、項(xiàng)目經(jīng)理(ViewGroup)、軟件工程師(View) 老板吧任務(wù)交給項(xiàng)目經(jīng)理,項(xiàng)目經(jīng)理認(rèn)為這個項(xiàng)目比較難,所以決定自己處理(ViewGroup#onInterceptTouchEvent,return true),項(xiàng)目經(jīng)理比較厲害他把任務(wù)完成了(ViewGroup#onTouchEvent,return true),然后他告訴老板他完成了(return true,ViewGroup#dispatchTouchEvent→Activity#dispatchTouchEvent)。之后老板依舊會把任務(wù)交給項(xiàng)目經(jīng)理,項(xiàng)目經(jīng)理知道這個任務(wù)難度,所以不假思索(也就是這個事件序列中的其余事件沒有經(jīng)過ViewGroup#onInterceptTouchEvent)的自己來做。

通過上面的例子,可以得出一些結(jié)論:

某個ViewGroup如果onInterceptTouchEvent返回為true,則ViewGroup攔截事件,將事件傳遞給其onTouchEvent方法進(jìn)行處理

某個ViewGroup如果它的onInterceptTouchEvent返回為true,那么這個事件序列中的后續(xù)事件,不會在進(jìn)行onInterceptTouchEvent的判斷,而是由它的dispatchTouchEvent方法直接傳遞給onTouchEvent方法進(jìn)行處理

2、在事件序列中攔截

這里把使用的示例恢復(fù)到初始狀態(tài),然后把我在ParentView#onInterceptTouchEvent方法,switch內(nèi)的兩個注釋掉的intercept = true;代碼進(jìn)行恢復(fù),最后部分intercept = true;再次注釋掉。

<?xml version="1.0" encoding="utf-8"?>
<com.idtk.customscroll.ParentView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:padding="10dp"
  tools:context="com.idtk.customscroll.MainActivity"
  >

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/zhiqinchun"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/hanzhan"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/shengui"
    android:clickable="true"/>

  <com.idtk.customscroll.ChildView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/dayu"
    android:clickable="true"/>

</com.idtk.customscroll.ParentView>

重新運(yùn)行之后,滑動一個圖片,來看看Log

 

這里分成兩張圖片,是因?yàn)橹虚g有很多ACTION_MOVE,為了方便觀察,所以只截取了Log的首尾部分。 這里的關(guān)鍵部分,就是紅框中的ACTION_CANCEL,可以看到ACTION_DOWN事件的傳遞時onInterceptTouchEvent并沒有攔截,返回false,在其后的事件ACTION_MOVE再次進(jìn)入onInterceptTouchEvent時,ViewGroup對事件進(jìn)行了攔截,這樣將會對View傳遞一個ACTION_CANCEL事件,之后的ACTION_MOVE事件就不再傳遞給View了。

使用工作中的情況來模擬:老板(Activity)、項(xiàng)目經(jīng)理(ViewGroup)、軟件工程師(View) 這里的情況就是,一期的任務(wù)和第一個例子一樣的情況一樣,由軟件工程師完成,不過忽然項(xiàng)目經(jīng)理覺得二期的任務(wù)有點(diǎn)難,然后決定自己完成。這時就給工程師說,這個項(xiàng)目的后續(xù)任務(wù),不要你來完成了(ACTION_CANCEL)。

從這里也可以得出一個結(jié)論:

某個View接收了ACTION_DOWN之后,這個序列的后續(xù)事件中,如果在某一刻被父View攔截了,則這個字View會收到一個ACTION_CANCEL事件,并且也不會再收到這個事件序列中的后續(xù)事件。

五、小結(jié)

本文通過示例打印出的各種Log對Android的事件分發(fā)機(jī)制進(jìn)行,得出如下結(jié)論。

  1. 一個事件序列是指從手指觸摸屏幕開始,到手指離開屏幕結(jié)束,這個過程中產(chǎn)生的一系列事件。一個事件序列以ACTION_DOWN事件開始,中間可能經(jīng)過若干個MOVE,以ACTION_UP事件結(jié)束。
  2. 事件的傳遞過程是由外向內(nèi)的,即事件總是由父元素分發(fā)給子元素
  3. 如果某個View消費(fèi)了ACTION_DOWN事件,那么通常情況下,這個事件序列中的后續(xù)事件也將交由其進(jìn)行處理,但可以通過調(diào)用其父View的onInterceptTouchEvent方法,對后續(xù)事件進(jìn)行攔截
  4. 如果某個View它不消耗ACTION_DOWN事件,那么這個序列的后續(xù)事件也不會再交由它來處理
  5. 如果事件沒有View對其進(jìn)行處理,那么最后將有Activity進(jìn)行處理
  6. 如果事件傳遞的結(jié)果為true,回傳的結(jié)果直接通過不斷調(diào)用父View#dispatchTouchEvent方法,傳遞給Activity;如果事件傳遞的結(jié)果為false,回傳的結(jié)果不斷調(diào)用父View#onTouchEvent方法,獲取返回結(jié)果。
  7. View默認(rèn)的onTouchEvent在View可點(diǎn)擊的情況下,將會消耗事件,返回true;不可點(diǎn)擊的情況下,則不消耗事件,返回false(longClickable的情況,讀者可以自行測試,結(jié)果與clickable相同)
  8. 如果某個ViewGroup的onInterceptTouchEvent返回為true,那么這個事件序列中的后續(xù)事件,不會在進(jìn)行onInterceptTouchEvent的判斷,而是由它的dispatchTouchEvent方法直接傳遞給onTouchEvent方法進(jìn)行處理
  9. 如果某個View接收了ACTION_DOWN之后,這個序列的后續(xù)事件中,在某一刻被父View攔截了,則這個字View會收到一個ACTION_CANCEL事件,并且也不會再收到這個事件序列中的后續(xù)事件

 

事件相關(guān)方法 方法功能 Activity ViewGroup View
public boolean dispatchTouchEvent 事件分發(fā) Yes Yes Yes
public boolean onInterceptTouchEvent 事件攔截 No Yes No
public boolean onTouchEvent 事件消費(fèi) Yes Yes Yes

以上就是對Android 事件分發(fā)的資料整理,后續(xù)繼續(xù)補(bǔ)充相關(guān)資料,謝謝大家對本站的支持!

相關(guān)文章

  • android listview初步學(xué)習(xí)實(shí)例代碼

    android listview初步學(xué)習(xí)實(shí)例代碼

    這篇文章主要介紹了android listview初步學(xué)習(xí)實(shí)例代碼,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • Android編程單元測試實(shí)例詳解(附源碼)

    Android編程單元測試實(shí)例詳解(附源碼)

    這篇文章主要介紹了Android編程單元測試,結(jié)合完整實(shí)例形式詳細(xì)分析了Android單元測試的具體步驟與相關(guān)技巧,并附帶完整實(shí)例代碼供讀者下載參考,需要的朋友可以參考下
    2015-11-11
  • Android RecyclerView添加頭部和底部的方法

    Android RecyclerView添加頭部和底部的方法

    這篇文章主要為大家詳細(xì)介紹了Android RecyclerView添加頭部和底部的方法,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android仿直播類app贈送禮物功能

    Android仿直播類app贈送禮物功能

    這篇文章主要介紹了Android仿直播類app贈送禮物功能,本文通過實(shí)例代碼效果圖展示的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-02-02
  • Flutter 快速實(shí)現(xiàn)聊天會話列表效果示例詳解

    Flutter 快速實(shí)現(xiàn)聊天會話列表效果示例詳解

    這篇文章主要為大家介紹了Flutter 快速實(shí)現(xiàn)聊天會話列表效果示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • fragment實(shí)現(xiàn)隱藏及界面切換效果

    fragment實(shí)現(xiàn)隱藏及界面切換效果

    這篇文章主要為大家詳細(xì)介紹了fragment實(shí)現(xiàn)隱藏及界面切換效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • Android中的webview支持頁面中的文件上傳實(shí)例代碼

    Android中的webview支持頁面中的文件上傳實(shí)例代碼

    本篇文章主要介紹了Android中的webview支持頁面中的文件上傳,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • Android?JetPack組件的支持庫Databinding詳解

    Android?JetPack組件的支持庫Databinding詳解

    DataBinding是Google發(fā)布的一個數(shù)據(jù)綁定框架,它能夠讓開發(fā)者減少重復(fù)性非常高的代碼,如findViewById這樣的操作。其核心優(yōu)勢是解決了數(shù)據(jù)分解映射到各個view的問題,在MVVM框架中,實(shí)現(xiàn)的View和Viewmode的雙向數(shù)據(jù)綁定
    2022-08-08
  • Android三種菜單實(shí)例分析

    Android三種菜單實(shí)例分析

    這篇文章主要介紹了Android三種菜單,較為詳細(xì)的分析了Android菜單分類及相關(guān)使用技巧,需要的朋友可以參考下
    2015-05-05
  • ijkPlayer播放器的全自動編譯腳本及最終編譯包

    ijkPlayer播放器的全自動編譯腳本及最終編譯包

    這篇文章主要介紹了ijkPlayer播放器的全自動編譯腳本及最終編譯包,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01

最新評論