国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android觸摸事件傳遞機制

2019-12-12 01:02:50
字體:
供稿:網(wǎng)友

前言:在Android開發(fā)中,經(jīng)常會遇到觸摸事件沖突,比如ViewPager的輪播圖跟Fragment的劃動事件沖突,或者輪播圖跟下拉事件沖突,自定義view的事件處理等,本文章將會詳細(xì)介紹Activity、View、ViewGroup三者的觸摸事件傳遞機制,傳遞包括三個階段:分發(fā)、攔截、消費。

本文章將會詳細(xì)介紹Activity、View、ViewGroup三者的觸摸事件傳遞機制,傳遞包括三個階段:分發(fā)、攔截、消費。

一.觸摸事件的類型

觸摸事件對應(yīng)的是 MotionEvent 類,事件類型主要有三種:

  1. ACTION_DOWN:用戶按下操作,表示一次觸摸事件的開始。
  2. ACTION_MOVE:在按下的情況下,進(jìn)行移動。輕微的移動都會傳遞到該事件。
  3. ACTION_UP:用戶手指離開屏幕,表示一次觸摸事件的

注 :如果用戶僅僅的是點擊而已,則只會執(zhí)行到 ACTION_DOWN 和 ACTION_UP 兩個事件,不會執(zhí)行到 ACTION_MOVE 事件。所以 ACTION_DOWN 和 ACTION_UP 是事件是必須的。

二.觸摸事件的傳遞階段

1.分發(fā)(Dispatch)

在Android系統(tǒng)中所有的觸摸事件都是由 dispatchTouchEvent 方法進(jìn)行分發(fā)的。該方法中判斷事件是被消費( return true ),還是繼續(xù)分發(fā)給子視圖處理( return super.dispatchTouchEvent ),如果當(dāng)前視圖是ViewGroup或者其子類,則會調(diào)用 onInterceptTouchEvent 判斷是否截攔。

@Override public boolean dispatchTouchEvent(MotionEvent event) {  return super.dispatchTouchEvent(event); }

2.截攔(Intercept)

事件的截攔 InterceptTouchEvent 只存在于ViewGroup及其子類,activity和View是不存在該方法。該方法判斷事件是被截攔 ( return true )并交給自身的 OnToucEvent 方法進(jìn)行消費,還是繼續(xù)傳遞給子視圖( return super.InterceptTouchEvent 或者 return false )。

@Override public boolean onInterceptTouchEvent(MotionEvent ev) {  return super.onInterceptTouchEvent(ev); }

3.消費(Consume)

事件的消費通過 OnTouchEvent 方法判斷,是被消費( return true ),還是不處理( return false )并將事件傳遞給父視圖的 OnTouchEvent 方法進(jìn)行處理。

@Override public boolean onTouchEvent(MotionEvent event) {  return super.onTouchEvent(event); }

所有擁有事件傳遞能力的類:

Activity: 擁有dispatchTouchEvent 、OnTouchEvent

ViewGroup: 擁有dispatchTouchEvent 、OnInterceptTouchEvent 、OnTouchEvent

View:擁有dispatchTouchEvent 、OnTouchEvent

三、View的事件傳遞機制

3.1 dome

雖然說ViewGroup是View的子類,但是這是說的View指的是除ViewGroup之外的View控件子類,首先定義一個MyTextView繼承TextView,打印每次事件的觸發(fā)以變了解事件傳遞的流程。

MyTextView 類

public class MyTextView extends TextView { private String tag = "MyTextView"; public MyTextView(Context context) {  super(context); } public MyTextView(Context context, AttributeSet attrs) {  super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent event) {  switch (event.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "dispatchTouchEvent ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "dispatchTouchEvent ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "dispatchTouchEvent ACTION_DOWN");    break;  }  return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) {  switch (event.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "onTouchEvent ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "onTouchEvent ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "onTouchEvent ACTION_DOWN");    break;  }  return super.onTouchEvent(event); }}

定義一個MainActivity來展現(xiàn)這個MyTextView,同時設(shè)置點擊(onClick)和觸摸(onTouch)監(jiān)聽。 MainActivity 類

public class MainActivity extends AppCompatActivity implements View.OnClickListener,View.OnTouchListener{ private MyTextView mMyTextView; private String tag = "MainActiviy"; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  mMyTextView = findViewById(R.id.text_view);  // 點擊監(jiān)聽  mMyTextView.setOnClickListener(this);  // 觸碰監(jiān)聽  mMyTextView.setOnTouchListener(this); } // MyTextView 點擊事件 @Override public void onClick(View view) {  switch (view.getId()){   case R.id.text_view:    Log.i(tag, "MyTextView onClick");    break;  } } // MyTextView 觸碰事件 @Override public boolean onTouch(View view, MotionEvent motionEvent) {  switch (motionEvent.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "MyTextView onTouch ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "MyTextView onTouch ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "MyTextView onTouch ACTION_DOWN");    break;  }  return false; } // Activity 的事件分發(fā) @Override public boolean dispatchTouchEvent(MotionEvent ev) {  switch (ev.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "dispatchTouchEvent ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "dispatchTouchEvent ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "dispatchTouchEvent ACTION_DOWN");    break;  }  return super.dispatchTouchEvent(ev); } // Activity 的事件消費 @Override public boolean onTouchEvent(MotionEvent event) {  switch (event.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "onTouchEvent ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "onTouchEvent ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "onTouchEvent ACTION_DOWN");    break;  }  return super.onTouchEvent(event); }}

3.2 打印日志

運行后,點擊Text View反饋的打印日志

03-28 08:05:14.824 1219-1219/com.mvp.chenzhesheng.androidadvance I/MainActiviy: dispatchTouchEvent ACTION_DOWN
03-28 08:05:14.824 1219-1219/com.mvp.chenzhesheng.androidadvance I/MyTextView: dispatchTouchEvent ACTION_DOWN
03-28 08:05:14.824 1219-1219/com.mvp.chenzhesheng.androidadvance I/MainActiviy: MyTextView onTouch ACTION_DOWN
03-28 08:05:14.824 1219-1219/com.mvp.chenzhesheng.androidadvance I/MyTextView: onTouchEvent ACTION_DOWN
03-28 08:05:15.034 1219-1219/com.mvp.chenzhesheng.androidadvance I/MainActiviy: dispatchTouchEvent ACTION_UP
03-28 08:05:15.034 1219-1219/com.mvp.chenzhesheng.androidadvance I/MyTextView: dispatchTouchEvent ACTION_UP
03-28 08:05:15.034 1219-1219/com.mvp.chenzhesheng.androidadvance I/MainActiviy: MyTextView onTouch ACTION_UP
03-28 08:05:15.034 1219-1219/com.mvp.chenzhesheng.androidadvance I/MyTextView: onTouchEvent ACTION_UP
03-28 08:05:15.044 1219-1219/com.mvp.chenzhesheng.androidadvance I/MainActiviy: MyTextView onClick

dispatchTouchEvent 、 OnTouchEvent 這兩個方法的返回值存在三種情況:

  1. 直接返回true。
  2. 直接返回false。
  3. 返回父類同名方法,super.dispatchTouchEvent 或者 super.OnTouchEvent。

由于擁有不同的返回值,所以事件傳遞流程也有不同,經(jīng)過不斷修改返回值測試,最終得到了點擊事件的流程圖,ACTION_DOWN 和 ACTION_UP 事件的傳遞流程是相同的。

3.3 事件傳遞流程圖

從上面的流程圖可以得出結(jié)論:

  1. 觸摸事件是從 dispatchTouchEvent 開始的,默認(rèn)返回父類同名方法 super ,事件將會依照嵌套層次從外向內(nèi)傳遞( MainActivity 到 MyTextView ),到達(dá)最內(nèi)層的 View 時,將由 View 的 OnTouchEvent 方法處理,該方法返回 true 時進(jìn)行消費不再傳遞,返回 false 時再由內(nèi)向外傳遞,由外層的 OnTouchEvent 處理。
  2. 如果外層向內(nèi)層傳遞過程中,人為干擾返回 true 消費,則不會繼續(xù)繼續(xù)像內(nèi)部傳遞。
  3. View 的事件控制順序先執(zhí)行 onTouch 再執(zhí)行 onClick ,如果 onTouch 返回 true 消費,則不會繼續(xù)傳遞,也不會執(zhí)行 onClick 方法。

四、ViewGroup的事件傳遞機制

4.1 dome

ViewGroup是 View 的控件容器存在,擁有 dispatchTouchEvent 、 onInterceptTouchEvent 和 onTouchEvent 三個方法,比 View 多了一個 onInterceptTouchEvent 方法。為了更好的觀察,我們需要自定義 MyRelativeLayout 繼承 RelativeLayout 。

MyRelativeLayout類

public class MyRelativeLayout extends RelativeLayout { private final static String tag = "MyRelativeLayout"; public MyRelativeLayout(Context context) {  super(context); } public MyRelativeLayout(Context context, AttributeSet attrs) {  super(context, attrs); } @Override public boolean dispatchTouchEvent(MotionEvent ev) {  switch (ev.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "dispatchTouchEvent ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "dispatchTouchEvent ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "dispatchTouchEvent ACTION_DOWN");    break;  }  return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  switch (ev.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "onInterceptTouchEvent ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "onInterceptTouchEvent ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "onInterceptTouchEvent ACTION_DOWN");    break;  }  return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) {  switch (event.getAction()){   case MotionEvent.ACTION_UP:    Log.i(tag, "onTouchEvent ACTION_UP");    break;   case MotionEvent.ACTION_MOVE:    Log.i(tag, "onTouchEvent ACTION_MOVE");    break;   case MotionEvent.ACTION_DOWN:    Log.i(tag, "onTouchEvent ACTION_DOWN");    break;  }  return super.onTouchEvent(event); }}

main_activity.xml 文件

<?xml version="1.0" encoding="utf-8"?><com.mvp.chenzhesheng.androidadvance.MyRelativeLayout 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" > <com.mvp.chenzhesheng.androidadvance.MyTextView  android:id="@+id/text_view"  android:clickable="true"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="Hello World!"</com.mvp.chenzhesheng.androidadvance.MyRelativeLayout>

4.2 打印日志

04-02 08:47:57.980 1030-1030/com.mvp.chenzhesheng.androidadvance I/MainActiviy: dispatchTouchEvent ACTION_DOWN
04-02 08:47:58.000 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyRelativeLayout: dispatchTouchEvent ACTION_DOWN
04-02 08:47:58.000 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyRelativeLayout: onInterceptTouchEvent ACTION_DOWN
04-02 08:47:58.000 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyTextView: dispatchTouchEvent ACTION_DOWN
04-02 08:47:58.010 1030-1030/com.mvp.chenzhesheng.androidadvance I/MainActiviy: MyTextView onTouch ACTION_DOWN
04-02 08:47:58.010 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyTextView: onTouchEvent ACTION_DOWN
04-02 08:47:58.200 1030-1030/com.mvp.chenzhesheng.androidadvance I/MainActiviy: dispatchTouchEvent ACTION_UP
04-02 08:47:58.200 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyRelativeLayout: dispatchTouchEvent ACTION_UP
04-02 08:47:58.200 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyRelativeLayout: onInterceptTouchEvent ACTION_UP
04-02 08:47:58.200 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyTextView: dispatchTouchEvent ACTION_UP
04-02 08:47:58.210 1030-1030/com.mvp.chenzhesheng.androidadvance I/MainActiviy: MyTextView onTouch ACTION_UP
04-02 08:47:58.210 1030-1030/com.mvp.chenzhesheng.androidadvance I/MyTextView: onTouchEvent ACTION_UP
04-02 08:47:58.260 1030-1030/com.mvp.chenzhesheng.androidadvance I/MainActiviy: MyTextView onClick

可以看到 MainActivity 和 MyTextView 的事件傳遞處理中添加了一層 MyRelativeLayout 。通過不同返回值測試,得到一套流程圖。

4.3 流程圖

從上面的流程圖可以得出結(jié)論:

  1. 觸摸事件傳遞是從 Activity 傳遞到 ViewGroup ,再傳遞到 View 。如果中間沒有 ViewGroup 則直接從 Activity 傳遞到 View 。
  2. ViewGroup 通過 onInterceptTouchEvent 方法對事件進(jìn)行截攔,如果返回 false 或者 super.onInterceptTouchEvent ,則事件會繼續(xù)傳遞給子 View 。
  3. 子 View 中對事件進(jìn)行消費后, ViewGroup 將不會接收到任何事件。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 金昌市| 乾安县| 高青县| 平乐县| 汉源县| 行唐县| 宝山区| 汕尾市| 泽库县| 富蕴县| 大连市| 米易县| 梅州市| 宁波市| 特克斯县| 连南| 滦南县| 平顶山市| 资源县| 四平市| 广西| 闽侯县| 巴楚县| 石首市| 贵溪市| 钟山县| 金坛市| 屏南县| 抚州市| 镶黄旗| 綦江县| 昂仁县| 常熟市| 三江| 金川县| 南康市| 顺平县| 冷水江市| 玉门市| 六枝特区| 石渠县|