自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android View事件機(jī)制21問21答

移動開發(fā)
Android View事件機(jī)制21問21答,有“View的坐標(biāo)參數(shù) 主要有哪些?分別有什么注意的要點?”等等。

[[178693]]

1.View的坐標(biāo)參數(shù) 主要有哪些?分別有什么注意的要點?

答:Left,Right,top,Bottom 注意這4個值其實就是 view 和 他的父控件的 相對坐標(biāo)值。 并非是距離屏幕左上角的絕對值,這點要注意。

此外,X和Y 其實也是相對于父控件的坐標(biāo)值。 TranslationX,TranslationY 這2個值 默認(rèn)都為0,是相對于父控件的左上角的偏移量。

換算關(guān)系:

x=left+tranX,y=top+tranY.

很多人不理解,為什么事這樣,其實就是View 如果有移動的話,比如平移這種,你們就要注意了,top和left 這種值 是不會變化的。

無論你把view怎么拖動,但是 x,y,tranX,tranY 的值是隨著拖動平移 而變化的。想明白這點 就行了。

2.onTouchEvent和GestureDetector 在什么時候用哪個比較好?

答:只有滑動需求的時候 就用前者,如果有雙擊等這種行為的時候 就用后者。

3.Scroller 用來解決什么問題?

答:view的scrollTo和scrollBy 滑動效果太差了,是瞬間完成。而scroller可以配合view的computeScroll 來完成 漸變的滑動效果。體驗更好。

4.ScrollTo和ScrollBy 有什么需要注意的?

答:前者是絕對滑動,后者是相對滑動?;瑒拥氖莢iew的內(nèi)容 而不是view本身。這很重要。比如textview 調(diào)用這2個方法 滑動的就是顯示出來的字的內(nèi)容。

一般而言 我們用scrollBy會比較多一些。傳值的話 其實 記住幾個法則就可以了。 右-左 x為正 否則x為負(fù) 上-下 y為負(fù),否則y為正。

可以稍微看一下 這2個的源碼:

  1. public void scrollTo(int x, int y) { 
  2.  
  3.         if (mScrollX != x || mScrollY != y) { 
  4.  
  5.             int oldX = mScrollX; 
  6.  
  7.             int oldY = mScrollY; 
  8.  
  9.             mScrollX = x; 
  10.  
  11.             mScrollY = y; 
  12.  
  13.             invalidateParentCaches(); 
  14.  
  15.             onScrollChanged(mScrollX, mScrollY, oldX, oldY); 
  16.  
  17.             if (!awakenScrollBars()) { 
  18.  
  19.                 postInvalidateOnAnimation(); 
  20.  
  21.             } 
  22.  
  23.         } 
  24.  
  25.     } 
  26.  
  27.  
  28.  public void scrollBy(int x, int y) { 
  29.  
  30.         scrollTo(mScrollX + x, mScrollY + y); 
  31.  
  32.     }  

看到里面有2個變量 mScrollX 和mScrollY 這2個東西沒,這2個單位的 值是像素,前者代表 view的左邊緣和view內(nèi)容左邊緣的距離。 后者代表 view上邊緣和view內(nèi)容上邊緣的距離。

5.使用動畫來實現(xiàn)view的滑動 有什么后果?

答:實際上view動畫 是對view的表面ui 也就是給用戶呈現(xiàn)出的視覺效果 來做的移動,動畫本身并不能移動view的真正位置。屬性動畫除外。動畫播放結(jié)束以后,view最終還是會回到自己的位置的,。當(dāng)然了你可以設(shè)置fillafter 屬性 來讓動畫播放結(jié)束以后 view表象停留在 變化以后的位置。所以這會帶來一個很嚴(yán)重的后果。比如你的button在屏幕的左邊,你現(xiàn)在用個動畫 并且設(shè)置了fillafter屬性讓他去了右邊。你會發(fā)現(xiàn) 點擊右邊的button 沒有click事件觸發(fā),但是點擊左邊的 卻可以觸發(fā),原因就是右邊的button 只是view的表象,真正的button 還在左邊沒有動過。你一定要這么做的話 可以提前在右邊button移動后的位置放一個新的button,當(dāng)你動畫執(zhí)行結(jié)束以后 把右邊的enable 左邊的讓他gone就可以了。

這么做就可以規(guī)避上述問題。

6.讓view滑動總共有幾種方式,分別要注意什么?都適用于那些場景?

答:總共有三種:

a:scrollto,scrollby。這種是最簡單的,但是只能滑動view的內(nèi)容 不可以滑動view本身。

b:動畫。動畫可以滑動view內(nèi)容,但是注意非屬性動畫 就如我們問題5說的內(nèi)容 會影響到交互,使用的時候要多注意。不過多數(shù)復(fù)雜的滑動效果都是屬性動畫來完成的,屬于大殺器級別、

c:改變布局參數(shù)。這種***理解了,無非是動態(tài)的通過java代碼來修改 margin等view的參數(shù)罷了。不過用的比較少。我本人不怎么用這種方法。

7.Scroller是干嘛的?原理是什么?

答:Scroller就是用于 讓view有滑動漸變效果的。用法如下:

  1. package com.example.administrator.motioneventtest; 
  2.  
  3.  
  4. import android.content.Context; 
  5.  
  6. import android.util.AttributeSet; 
  7.  
  8. import android.widget.Scroller; 
  9.  
  10. import android.widget.TextView; 
  11.  
  12.  
  13. /** 
  14.  
  15.  * Created by Administrator on 2016/2/2. 
  16.  
  17.  */ 
  18.  
  19. public class CustomTextView extends TextView{ 
  20.  
  21.  
  22.     private Scroller mScroller; 
  23.  
  24.  
  25.  
  26.     public CustomTextView(Context context) { 
  27.  
  28.         super(context); 
  29.  
  30.         mScroller=new Scroller(context); 
  31.  
  32.     } 
  33.  
  34.  
  35.     public CustomTextView(Context context, AttributeSet attrs) { 
  36.  
  37.         super(context, attrs); 
  38.  
  39.         mScroller=new Scroller(context); 
  40.  
  41.  
  42.     } 
  43.  
  44.  
  45.     public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) { 
  46.  
  47.         super(context, attrs, defStyleAttr); 
  48.  
  49.         mScroller=new Scroller(context); 
  50.  
  51.  
  52.     } 
  53.  
  54.  
  55.     //調(diào)用此方法滾動到目標(biāo)位置 
  56.  
  57.     public void smoothScrollTo(int fx, int fy) { 
  58.  
  59.         int dx = fx - mScroller.getFinalX(); 
  60.  
  61.         int dy = fy - mScroller.getFinalY(); 
  62.  
  63.         smoothScrollBy(dx, dy); 
  64.  
  65.     } 
  66.  
  67.  
  68.     //調(diào)用此方法設(shè)置滾動的相對偏移 
  69.  
  70.     public void smoothScrollBy(int dx, int dy) { 
  71.  
  72.  
  73.         //設(shè)置mScroller的滾動偏移量 
  74.  
  75.         mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy,4000); 
  76.  
  77.         invalidate();//這里必須調(diào)用invalidate()才能保證computeScroll()會被調(diào)用,否則不一定會刷新界面,看不到滾動效果 
  78.  
  79.     } 
  80.  
  81.  
  82.     //使用scroller最重要不要遺漏這個方法 
  83.  
  84.     @Override 
  85.  
  86.     public void computeScroll() { 
  87.  
  88.         if (mScroller.computeScrollOffset()) 
  89.  
  90.         { 
  91.  
  92.             scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); 
  93.  
  94.             //這個方法不要忘記調(diào)用。 
  95.  
  96.             postInvalidate(); 
  97.  
  98.         } 
  99.  
  100.         super.computeScroll(); 
  101.  
  102.     } 
  103.  
  104.  

其實上述代碼 很多人應(yīng)該都能搜到。我們這里主要講一下 他的原理。 

  1. //參數(shù)很好理解 前面滑動起始點 中間滑動距離 ***一個是 漸變時間 
  2.  
  3. //而且我們看到startScroll 這個方法就是設(shè)置了一下參數(shù) 并沒有什么滑動的代碼在 
  4.  
  5. //回到前面的demo能看到我們通常調(diào)用完這個方法以后 都會馬上調(diào)用invalidate()方法 
  6.  
  7.  public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
  8.  
  9.         mMode = SCROLL_MODE; 
  10.  
  11.         mFinished = false
  12.  
  13.         mDuration = duration; 
  14.  
  15.         mStartTime = AnimationUtils.currentAnimationTimeMillis(); 
  16.  
  17.         mStartX = startX; 
  18.  
  19.         mStartY = startY; 
  20.  
  21.         mFinalX = startX + dx; 
  22.  
  23.         mFinalY = startY + dy; 
  24.  
  25.         mDeltaX = dx; 
  26.  
  27.         mDeltaY = dy; 
  28.  
  29.         mDurationReciprocal = 1.0f / (float) mDuration; 
  30.  
  31.     } 
  32.  
  33.  
  34.  
  35. //我們都知道invalidate 會觸發(fā)view的 draw方法  
  36.  
  37. //我們跟進(jìn)去看 會發(fā)現(xiàn)draw方法里 會調(diào)用下面的代碼: 
  38.  
  39. //也就是說會調(diào)用    computeScroll方法 而view本身這個方法 
  40.  
  41. //是空的所以會留給我們自己實現(xiàn) 
  42.  
  43.  int sx = 0; 
  44.  
  45.         int sy = 0; 
  46.  
  47.         if (!drawingWithRenderNode) { 
  48.  
  49.             computeScroll(); 
  50.  
  51.             sx = mScrollX; 
  52.  
  53.             sy = mScrollY; 
  54.  
  55.         } 
  56.  
  57.  
  58.  
  59. //然后回到我們的customtextview 可以看到我們實現(xiàn)的    computeScroll方法如下: 
  60.  
  61. //你看在這個方法里 我們調(diào)用了scrollTo方法 來實現(xiàn)滑動,滑動結(jié)束以后再次觸發(fā)view的重繪 
  62.  
  63. //然后又會再次觸發(fā)computeScroll 實現(xiàn)一個循環(huán)。 
  64.  
  65. public void computeScroll() { 
  66.  
  67.         if (mScroller.computeScrollOffset()) 
  68.  
  69.         { 
  70.  
  71.             scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); 
  72.  
  73.             //這個方法不要忘記調(diào)用。 
  74.  
  75.             postInvalidate(); 
  76.  
  77.         } 
  78.  
  79.         super.computeScroll(); 
  80.  
  81.     }  
  82.  
  83.  
  84.  
  85. //返回true就代表滑動還沒結(jié)束 false就是結(jié)束了 
  86.  
  87. //其實這個方法 就跟屬性動畫里的插值器一樣 你在使用startScroll方法的時候 會傳一個事件的值, 
  88.  
  89. //這個方法就是根據(jù)這個事件的值來計算你每一次scrollx和scrolly的值 
  90.  
  91. public boolean computeScrollOffset() { 
  92.  
  93.         if (mFinished) { 
  94.  
  95.             return false
  96.  
  97.         } 
  98.  
  99.  
  100.         int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); 
  101.  
  102.      
  103.  
  104.         if (timePassed < mDuration) { 
  105.  
  106.             switch (mMode) { 
  107.  
  108.             case SCROLL_MODE: 
  109.  
  110.                 final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal); 
  111.  
  112.                 mCurrX = mStartX + Math.round(x * mDeltaX); 
  113.  
  114.                 mCurrY = mStartY + Math.round(x * mDeltaY); 
  115.  
  116.                 break; 
  117.  
  118.             case FLING_MODE: 
  119.  
  120.                 final float t = (float) timePassed / mDuration; 
  121.  
  122.                 final int index = (int) (NB_SAMPLES * t); 
  123.  
  124.                 float distanceCoef = 1.f; 
  125.  
  126.                 float velocityCoef = 0.f; 
  127.  
  128.                 if (index < NB_SAMPLES) { 
  129.  
  130.                     final float t_inf = (floatindex / NB_SAMPLES; 
  131.  
  132.                     final float t_sup = (float) (index + 1) / NB_SAMPLES; 
  133.  
  134.                     final float d_inf = SPLINE_POSITION[index]; 
  135.  
  136.                     final float d_sup = SPLINE_POSITION[index + 1]; 
  137.  
  138.                     velocityCoef = (d_sup - d_inf) / (t_sup - t_inf); 
  139.  
  140.                     distanceCoef = d_inf + (t - t_inf) * velocityCoef; 
  141.  
  142.                 } 
  143.  
  144.  
  145.                 mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f; 
  146.  
  147.                  
  148.  
  149.                 mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX)); 
  150.  
  151.                 // Pin to mMinX <= mCurrX <= mMaxX 
  152.  
  153.                 mCurrX = Math.min(mCurrX, mMaxX); 
  154.  
  155.                 mCurrX = Math.max(mCurrX, mMinX); 
  156.  
  157.                  
  158.  
  159.                 mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY)); 
  160.  
  161.                 // Pin to mMinY <= mCurrY <= mMaxY 
  162.  
  163.                 mCurrY = Math.min(mCurrY, mMaxY); 
  164.  
  165.                 mCurrY = Math.max(mCurrY, mMinY); 
  166.  
  167.  
  168.                 if (mCurrX == mFinalX && mCurrY == mFinalY) { 
  169.  
  170.                     mFinished = true
  171.  
  172.                 } 
  173.  
  174.  
  175.                 break; 
  176.  
  177.             } 
  178.  
  179.         } 
  180.  
  181.         else { 
  182.  
  183.             mCurrX = mFinalX; 
  184.  
  185.             mCurrY = mFinalY; 
  186.  
  187.             mFinished = true
  188.  
  189.         } 
  190.  
  191.         return true
  192.  
  193.     }  

8.view的滑動漸變效果總共有幾種方法?

答:三種,***種是scroller 也是使用最多的。問題7里有解釋。還有一種就是動畫,動畫我就不多說了,不屬于本文范疇。***一種也是我們經(jīng)常使用的就是用handler ,每隔一個時間間隔 來更新view的狀態(tài)。

代碼不寫了很簡單。 自行體會。

9.view的事件傳遞機(jī)制 如何用偽代碼來表示?

答:

  1. /** 
  2.  
  3.      * 對于一個root viewgroup來說,如果接受了一個點擊事件,那么首先會調(diào)用他的dispatchTouchEvent方法。 
  4.  
  5.      * 如果這個viewgroup的onInterceptTouchEvent 返回true,那就代表要攔截這個事件。接下來這個事件就 
  6.  
  7.      * 給viewgroup自己處理了,從而viewgroup的onTouchEvent方法就會被調(diào)用。如果如果這個viewgroup的onInterceptTouchEvent 
  8.  
  9.      * 返回false就代表我不攔截這個事件,然后就把這個事件傳遞給自己的子元素,然后子元素的dispatchTouchEvent 
  10.  
  11.      * 就會被調(diào)用,就是這樣一個循環(huán)直到 事件被處理。 
  12.  
  13.      * 
  14.  
  15.      */ 
  16.  
  17. public boolean dispatchTouchEvent(MotionEvent ev) 
  18.  
  19.  
  20.     boolean consume=false
  21.  
  22.     if (onInterceptTouchEvent(ev)) { 
  23.  
  24.         consume=onTouchEvent(ev); 
  25.  
  26.     }else 
  27.  
  28.     { 
  29.  
  30.         consume=child.dispatchTouchEvent(ev); 
  31.  
  32.     } 
  33.  
  34.     return consume; 
  35.  
  36.  

10.view的onTouchEvent,OnClickListerner和OnTouchListener的onTouch方法 三者優(yōu)先級如何?

答:onTouchListener優(yōu)先級***,如果onTouch方法返回 false ,那onTouchEvent就被調(diào)用了,返回true 就不會被調(diào)用。至于onClick 優(yōu)先級***。

11.點擊事件的傳遞順序如何?

答:Activity-Window-View。從上到下依次傳遞,當(dāng)然了如果你***的那個view onTouchEvent返回false 那就說明他不想處理 那就再往上拋,都不處理的話

最終就還是讓Activity自己處理了。舉個例子,pm下發(fā)一個任務(wù)給leader,leader自己不做 給架構(gòu)師a,小a也不做 給程序員b,b如果做了那就結(jié)束了這個任務(wù)。

b如果發(fā)現(xiàn)自己搞不定,那就找a做,a要是也搞不定 就會不斷向上發(fā)起請求,最終可能還是pm做。 

  1. //activity的dispatchTouchEvent 方法 一開始就是交給window去處理的 
  2.  
  3. //win的superDispatchTouchEvent 返回true 那就直接結(jié)束了 這個函數(shù)了。返回false就意味 
  4.  
  5. //這事件沒人處理,最終還是給activity的onTouchEvent 自己處理 這里的getwindow 其實就是phonewindow 
  6.  
  7.  public boolean dispatchTouchEvent(MotionEvent ev) { 
  8.  
  9.         if (ev.getAction() == MotionEvent.ACTION_DOWN) { 
  10.  
  11.             onUserInteraction(); 
  12.  
  13.         } 
  14.  
  15.         if (getWindow().superDispatchTouchEvent(ev)) { 
  16.  
  17.             return true
  18.  
  19.         } 
  20.  
  21.         return onTouchEvent(ev); 
  22.  
  23.     } 
  24.  
  25.  
  26.  
  27. //來看phonewindow的這個函數(shù) 直接把事件傳遞給了mDecor 
  28.  
  29.  
  30.  @Override 
  31.  
  32.     public boolean superDispatchTouchEvent(MotionEvent event) { 
  33.  
  34.         return mDecor.superDispatchTouchEvent(event); 
  35.  
  36.     } 
  37.  
  38.  
  39. //devorview就是 我們的rootview了 就是那個framelayout 我們的setContentView里面?zhèn)鬟f的那個layout 
  40.  
  41. //就是這個decorview的 子view了 
  42.  
  43.      @Override 
  44.  
  45.     public final View getDecorView() { 
  46.  
  47.         if (mDecor == null) { 
  48.  
  49.             installDecor(); 
  50.  
  51.         } 
  52.  
  53.         return mDecor; 
  54.  
  55.     }  

12.事件分為幾個步驟?

答:down事件開頭,up事件結(jié)尾,中間可能會有數(shù)目不定的move事件。

13.ViewGroup如何對點擊事件分發(fā)?

答:

  1. viewgroup就是在actionMasked == MotionEvent.ACTION_DOWN 和 mFirstTouchTarget != null 這兩種情況來判斷是否會進(jìn)入攔截事件的流程 
  2.  
  3.  
  4. 看代碼可以知道 如果是ACTION_DOWN事件  那就肯定進(jìn)入 是否要攔截事件的流程 
  5.  
  6.  
  7. 如果不是ACTION_DOWN事件 那就要看mFirstTouchTarget != null 這個條件是否成立 
  8.  
  9.  
  10. 這個地方有點繞但是也好理解,其實就是 對于一個事件序列來說 down是事件的開頭 所以肯定進(jìn)入了這個事件是否攔截的流程 也就是if 括號內(nèi)。 
  11.  
  12.  
  13.  
  14. mFirstTouchTarget其實是一個單鏈表結(jié)構(gòu)他指向的是 成功處理事件的子元素。 
  15.  
  16.  
  17. 也就是說 如果有子元素成功處理了 事件,那這個值就不為NULL。反過來說 
  18.  
  19.  
  20. 只要viewgroup攔截了事件,mFirstTouchTarget就不為NULL,所以括號內(nèi)就不會執(zhí)行,也就側(cè)面說明了一個結(jié)論: 
  21.  
  22.  
  23. 某個view 一旦決定攔截事件,那么這個事件所屬的事件序列 都只能由他來執(zhí)行。并且onInterceptTouchEvent 這個方法不會被調(diào)用了 
  24.  
  25.  
  26.             final boolean intercepted; 
  27.  
  28.             if (actionMasked == MotionEvent.ACTION_DOWN 
  29.  
  30.                     || mFirstTouchTarget != null) { 
  31.  
  32.                 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 
  33.  
  34.                 if (!disallowIntercept) { 
  35.  
  36.                     intercepted = onInterceptTouchEvent(ev); 
  37.  
  38.                     ev.setAction(action); // restore action in case it was changed 
  39.  
  40.                 } else { 
  41.  
  42.                     intercepted = false
  43.  
  44.                 } 
  45.  
  46.             } else { 
  47.  
  48.                 // There are no touch targets and this action is not an initial down 
  49.  
  50.                 // so this view group continues to intercept touches. 
  51.  
  52.                 intercepted = true
  53.  
  54.             }  

14.如果某個view 處理事件的時候 沒有消耗down事件 會有什么結(jié)果?

答:假如一個view,在down事件來的時候 他的onTouchEvent返回false, 那么這個down事件 所屬的事件序列 就是他后續(xù)的move 和up 都不會給他處理了,全部都給他的父view處理。

15.如果view 不消耗move或者up事件 會有什么結(jié)果?

答:那這個事件所屬的事件序列就消失了,父view也不會處理的,最終都給activity 去處理了。

16.ViewGroup 默認(rèn)攔截事件嗎?

答:默認(rèn)不攔截任何事件,onInterceptTouchEvent返回的是false。

17.一旦有事件傳遞給view,view的onTouchEvent一定會被調(diào)用嗎?

答:是的,因為view 本身沒有onInterceptTouchEvent方法,所以只要事件來到view這里 就一定會走onTouchEvent方法。

并且默認(rèn)都是消耗掉,返回true的。除非這個view是不可點擊的,所謂不可點擊就是clickable和longgclikable同時為fale

Button的clickable就是true 但是textview是false。

18.enable是否影響view的onTouchEvent返回值?

答:不影響,只要clickable和longClickable有一個為真,那么onTouchEvent就返回true。

19.requestDisallowInterceptTouchEvent 可以在子元素中干擾父元素的事件分發(fā)嗎?如果可以,是全部都可以干擾嗎?

答:肯定可以,但是down事件干擾不了。

20.dispatchTouchEvent每次都會被調(diào)用嗎?

答:是的,onInterceptTouchEvent則不會。

21.滑動沖突問題如何解決 思路是什么?

答。要解決滑動沖突 其實最主要的就是有一個核心思想。你到底想在一個事件序列中,讓哪個view 來響應(yīng)你的滑動?比如 從上到下滑,是哪個view來處理這個事件,從左到右呢?

用業(yè)務(wù)需求 來想明白以后 剩下的 其實就很好做了。核心的方法 就是2個 外部攔截也就是父親攔截,另外就是內(nèi)部攔截,也就是子view攔截法。 學(xué)會這2種 基本上所有的滑動沖突

都是這2種的變種,而且核心代碼思想都一樣。

外部攔截法:思路就是重寫父容器的onInterceptTouchEvent即可。子元素一般不需要管。可以很容易理解,因為這和android自身的事件處理機(jī)制 邏輯是一模一樣的 

  1. @Override 
  2.  
  3.     public boolean onInterceptTouchEvent(MotionEvent ev) { 
  4.  
  5.  
  6.         boolean intercepted = false
  7.  
  8.         int x = (int) ev.getX(); 
  9.  
  10.         int y = (int) ev.getY(); 
  11.  
  12.  
  13.         switch (ev.getAction()) { 
  14.  
  15.             //down事件肯定不能攔截 攔截了后面的就收不到了 
  16.  
  17.             case MotionEvent.ACTION_DOWN: 
  18.  
  19.                 intercepted = false
  20.  
  21.                 break; 
  22.  
  23.             case MotionEvent.ACTION_MOVE: 
  24.  
  25.                 if (你的業(yè)務(wù)需求) { 
  26.  
  27.                     //如果確定攔截了 就去自己的onTouchEvent里 處理攔截之后的操作和效果 即可了 
  28.  
  29.                     intercepted = true
  30.  
  31.                 } else { 
  32.  
  33.                     intercepted = false
  34.  
  35.                 } 
  36.  
  37.                 break; 
  38.  
  39.             case MotionEvent.ACTION_UP: 
  40.  
  41.                 //up事件 我們一般都是返回false的 一般父容器都不會攔截他。 因為up是事件的***一步。這里返回true也沒啥意義 
  42.  
  43.                 //唯一的意義就是因為 父元素 up被攔截。導(dǎo)致子元素 收不到up事件,那子元素 就肯定沒有onClick事件觸發(fā)了,這里的 
  44.  
  45.                 //小細(xì)節(jié) 要想明白 
  46.  
  47.                 intercepted = false
  48.  
  49.                 break; 
  50.  
  51.             default
  52.  
  53.                 break; 
  54.  
  55.         } 
  56.  
  57.         return intercepted; 
  58.  
  59.     }  

內(nèi)部攔截法:內(nèi)部攔截法稍微復(fù)雜一點,就是事件到來的時候,父容器不管,讓子元素自己來決定是否處理。如果消耗了 就***,沒消耗 自然就轉(zhuǎn)給父容器處理了。

子元素代碼: 

  1. @Override 
  2.  
  3.     public boolean dispatchTouchEvent(MotionEvent event) { 
  4.  
  5.         int x = (int) event.getX(); 
  6.  
  7.         int y = (int) event.getY(); 
  8.  
  9.         switch (event.getAction()) { 
  10.  
  11.             case MotionEvent.ACTION_DOWN: 
  12.  
  13.                 getParent().requestDisallowInterceptTouchEvent(true); 
  14.  
  15.                 break; 
  16.  
  17.             case MotionEvent.ACTION_MOVE: 
  18.  
  19.                 if (如果父容器需要這個點擊事件) { 
  20.  
  21.                     getParent().requestDisallowInterceptTouchEvent(false); 
  22.  
  23.                 }//否則的話 就交給自己本身view的onTouchEvent自動處理了 
  24.  
  25.                 break; 
  26.  
  27.             case MotionEvent.ACTION_UP: 
  28.  
  29.                 break; 
  30.  
  31.             default
  32.  
  33.                 break; 
  34.  
  35.         } 
  36.  
  37.         return super.dispatchTouchEvent(event); 
  38.  
  39.     }  

父親容器代碼也要修改一下,其實就是保證父親別攔截down: 

  1. @Override 
  2.  
  3.     public boolean onInterceptTouchEvent(MotionEvent ev) { 
  4.  
  5.  
  6.         if (ev.getAction() == MotionEvent.ACTION_DOWN) { 
  7.  
  8.             return false
  9.  
  10.  
  11.         } 
  12.  
  13.         return true
  14.  
  15.     }  
責(zé)任編輯:龐桂玉 來源: 安卓開發(fā)精選
相關(guān)推薦

2021-08-17 13:41:11

AndroidView事件

2012-02-24 10:28:32

2023-10-08 08:23:44

Android事件邏輯

2010-05-28 15:47:16

雙絞線

2022-04-01 08:37:07

SpringAPI前端

2012-10-31 09:41:47

WAN優(yōu)化SSLHTTPS

2014-12-15 11:16:34

vCenter SRM

2022-11-14 12:38:29

2016-12-08 10:19:18

Android事件分發(fā)機(jī)制

2011-08-05 11:06:33

VMware vSph虛擬化

2011-11-03 09:29:32

2023-11-06 11:13:58

Bean占位符標(biāo)記

2020-04-10 10:11:15

數(shù)據(jù)泄露漏洞信息安全

2023-10-09 08:18:08

域值Java 21結(jié)構(gòu)化

2014-05-08 09:37:09

Fedora 21發(fā)布日程

2019-12-06 09:30:55

curl命令Linux

2011-03-14 14:40:28

VMware Work

2011-12-08 09:47:08

虛擬化應(yīng)用虛擬化

2009-12-02 15:02:17

路由器怎么安裝

2013-04-24 11:15:56

Android開發(fā)Touch事件傳遞機(jī)制
點贊
收藏

51CTO技術(shù)棧公眾號