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

首頁 > 系統 > Android > 正文

Android事件分發機制(下) View的事件處理

2019-12-12 04:01:20
字體:
來源:轉載
供稿:網友

綜述

  在上篇文章Android中的事件分發機制(上)――ViewGroup的事件分發中,對ViewGroup的事件分發進行了詳細的分析。在文章的最后ViewGroup的dispatchTouchEvent方法調用dispatchTransformedTouchEvent方法成功將事件傳遞給ViewGroup的子View。并交由子View進行處理。那么現在就來分析一下子View接收到事件以后是如何處理的。

View的事件處理

  對于這里描述的View,它是ViewGroup的父類,并不包含任何的子元素。這也就意味著View無法再次向下對事件進行分發操作,因此在View中并不存在onInterceptTouchEvent方法,也不會對事件做出攔截操作。它所做的事情就是對所接收的事件進行處理。下面就開看一下View如何對事件進行處理的。
  既然ViewGroup將事件交由View的dispatchTouchEvent方。那么首先在這里就來看一下dispatchTouchEvent里面做了什么事情。

public boolean dispatchTouchEvent(MotionEvent event) {  ......  if (onFilterTouchEventForSecurity(event)) {    //noinspection SimplifiableIfStatement    ListenerInfo li = mListenerInfo;    if (li != null && li.mOnTouchListener != null        && (mViewFlags & ENABLED_MASK) == ENABLED        && li.mOnTouchListener.onTouch(this, event)) {      result = true;    }    if (!result && onTouchEvent(event)) {      result = true;    }  }  ......  return result;}

  在View的dispatchTouchEvent方法中對事件處理的核心部分體現在上述代碼中。onFilterTouchEventForSecurity方法表示當前接收事件的view是否處于被遮蓋狀態,View處于被遮蓋狀態表示當前View不位于頂部,該view被其它View所覆蓋。如果當前View被遮蓋,那么該View不會對事件進行處理。

public interface OnTouchListener {  boolean onTouch(View v, MotionEvent event);}public void setOnTouchListener(OnTouchListener l) {  getListenerInfo().mOnTouchListener = l;}ListenerInfo getListenerInfo() {  if (mListenerInfo != null) {    return mListenerInfo;  }  mListenerInfo = new ListenerInfo();  return mListenerInfo;}

  在結合上述一段代碼可以看到,通過setOnTouchListener方法設置OnTouchListener以后,若是當前View處于可用狀態,那么條件li != null && li.mOnTouchListener !=null && (mViewFlags & ENABLED_MASK) == ENABLED必然為true。這時候程序便會回調OnTouchListener中的onTouch方法,若是在onTouch方法中返回true,便不會在執行View的onTouchEvent方法。從這里我們能夠看到,一旦設置了OnTouchListener,那么OnTouchListener的優先級要高于onTouchEvent。
  有一點需要注意,在程序中設置了OnTouchListener以后,對于OnTouchListener中的onTouch的返回值并不代表View中的dispatchTouchEvent方法所返回的值。在onTouch方法返回true的時候,表示事件成功被當前View所消耗,這時候result被置為true并且不再執行onTouchEvent,所以dispatchTouchEvent也就返回true。可是一旦在onTouch方法中返回false。這時候便會調用onTouchEvent方法,如果事件被onTouchEvent成功處理,并返回true,result依然會被置為true,dispatchTouchEvent自然而然的也就返回true。
  下面在進入View的onTouchEvent方法一探究竟。對于onTouchEvent方法里的內容比較多,在這里分段查看。

if ((viewFlags & ENABLED_MASK) == DISABLED) {  if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {    setPressed(false);  }  // A disabled view that is clickable still consumes the touch  // events, it just doesn't respond to them.  return (((viewFlags & CLICKABLE) == CLICKABLE      || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)      || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);}

  在這里可以看出對于不可用的View,如果他們的一些點擊事件可用的話,依然能夠成功的消費事件,只是它不會為該事件做出響應。對于View的這些點擊之間默認為不可用,但是對于不同的的View他們的默認值不一樣。例如在ImageView中點擊事件依然為不可用,但是在Button中點擊事件為可用。當然如果手動為它們設置監聽事件,那么這些監聽事件都將會自動被設為可用狀態。從如下源碼中可以看出。

public void setOnClickListener(@Nullable OnClickListener l) {  if (!isClickable()) {    setClickable(true);  }  getListenerInfo().mOnClickListener = l;}public void setOnLongClickListener(@Nullable OnLongClickListener l) {  if (!isLongClickable()) {    setLongClickable(true);  }  getListenerInfo().mOnLongClickListener = l;}public void setOnContextClickListener(@Nullable OnContextClickListener l) {  if (!isContextClickable()) {    setContextClickable(true);  }  getListenerInfo().mOnContextClickListener = l;}  下面接著看OnTouchEvent里面代碼。if (mTouchDelegate != null) {  if (mTouchDelegate.onTouchEvent(event)) {    return true;  }}

  這里首先判斷是否對事件設置了代理,如果對事件設置了代理,便會執行TouchDelegate的onTouchEvent方法。mTouchDelegate默認值為null,可以通過View的setTouchDelegate方法來設置代理。對于TouchDelegate在后續的文章中在進行詳細分析,在這里就不在過多描述。
  最后看一下View是如何處理事件的,對于接收的事件整個處理過程比較復雜,在這里就從宏觀上來整體看一下它的處理機制。

if (((viewFlags & CLICKABLE) == CLICKABLE ||    (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||    (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {  switch (action) {    case MotionEvent.ACTION_UP:      ......        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {          // This is a tap, so remove the longpress check          removeLongPressCallback();          // Only perform take click actions if we were in the pressed state          if (!focusTaken) {            // Use a Runnable and post this rather than calling            // performClick directly. This lets other visual state            // of the view update before click actions start.            if (mPerformClick == null) {              mPerformClick = new PerformClick();            }            if (!post(mPerformClick)) {              performClick();            }          }        }      ......      break;    ......  }  return true;}

  如果View的點擊事件處于可用狀態的話,便會對于這些事件進行處理,并且返回true。當一個事件序列完成以后調用performClick方法,下面看下這個performClick方法。

public boolean performClick() {  final boolean result;  final ListenerInfo li = mListenerInfo;  if (li != null && li.mOnClickListener != null) {    playSoundEffect(SoundEffectConstants.CLICK);    li.mOnClickListener.onClick(this);    result = true;  } else {    result = false;  }  sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);  return result;}

  從上面代碼中可以看出,如果我們設置了OnClickListener,便會調用它的onClick方法。從這一路下來我們可以看出對于View的onClick事件,在最后才會被調用,可見onClick的優先級是最低的。

總結

  在這里對View的事件處理做一下總結。在ViewGroup將事件分發到View以后。在View里面通過OnTouchListener的onTouch和View中的onTouchEvent這兩個方法對事件進行處理。對于onTouch方法是View提供給用戶的,方便用戶自己處理觸摸事件,而onTouchEvent是Android系統自己實現的接口。若是用戶設置了OnTouchListener,Android系統會首先調用OnTouchListener的onTouch方法。若是在onTouch方法中返回true,就不在執行View的onTouchEvent方法。只有在onTouch中返回了false才會執行onTouchEvent。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 环江| 大新县| 九台市| 右玉县| 齐河县| 栾城县| 南川市| 万全县| 宝山区| 镇雄县| 泉州市| 马山县| 兴文县| 始兴县| 许昌县| 原阳县| 宾阳县| 邵阳市| 宁国市| 交城县| 平远县| 始兴县| 博湖县| 建德市| 全州县| 临漳县| 湖州市| 阿城市| 长子县| 抚顺县| 资中县| 丁青县| 普定县| 临夏市| 锦屏县| 磐石市| 建平县| 建平县| 沈阳市| 晋州市| 哈巴河县|