衝突的緣由
電腦原本設計好了最簡單的規則,down事件碰到哪一個控件,哪一個控件就接收所有事件,是原始的以人爲本!
但人恰恰喜歡打破規則。或者是偷懶,便捷緣故,如scrollView.不須要設計旁邊下拉條。人就想往中間拉,管你碰到中間什麼控件,我就要滑動的事件。
爲何電腦端沒有這麼多衝突?由於電腦端時代,是鍵盤,和鼠標,人還算守規則,要滑動,用滾動條啊,有了觸摸後。拉什麼拉,我要流的滑。
因此出現了截斷,截斷就像是潘多拉之盒,雖然有了截斷的便利,也帶來了世界的混亂。
由於事件的處理是從控件樹的上層到下層,截斷後,上下之間順序優先獨佔,雖然對於scorllview,大部分是ok的。
但有時候這又和咱們人類感受的不匹配。爲何下滑裏面的不讓下滑,由於下滑不知道里面還有下滑啊,下滑必須掌控下滑動做。不行,下滑碰到下滑,要給裏面下滑。 等等。
因此纔會產生控件間事件該如何分配的問題。
因此總結
電腦的設計(無衝突,有時候不那麼方便):down碰到誰給誰,鐵通常的紀律。要滑動,用滾動條。
人類的感受(所有截斷):0.有時候,手碰到了子控件,仍是要把事件給上層,因此就產生了截斷,打開了混亂的源頭。如scorllview:在子控件上滑動,事件還要歸scrollview。
人類的感受(外部截斷):1.有時候,上層截斷後,須要把上層不須要的動做,分配給下層。 因此須要上層,精確控制本身的截取,放行本身不須要的。
人類的感受(內部截斷):2.有時候,上層截斷後,須要把下層須要的動做, 分配給下層。因此須要上層,先放行down, 讓下層執行getparent().disallowinterxxxxx. 這樣讓下層掌握控制權。
個人感受:優先碰到誰給誰,若是必定要截斷,那麼只截取本身的。若是子和我要搶同一個事件,那麼優先看看是否能夠避免這種設計。因此儘可能不用getparent().disallowinter.
儘可能用外部截斷法來分配滑動,由於簡潔,容易理解和定位bug,只有一種狀況是必須使用內部截斷法的。就是內外須要分配的事件是同一個,從業務上沒法區分的動做,並且此動做應該給子控件。那麼就必須內部截斷法。
因此原本,從下往上一個listener.touch就能夠工做。一切的起源都是上層想要截斷事件。因此纔有onintercetp+ontouch. 爲了解決截斷的特殊狀況又出現了disallowflag. click感受是一個動做語法糖而已。
我的名詞修正java
滑動衝突,由於修改成滑動分配。這樣更容易理解本質。
由於本質上就是如何分配事件。無論和外部截斷和內部截斷。
截斷的目的就是分配。
diapatchEvent:我的感受應該翻譯爲下發,而不是分發。
有3個蘋果,都給一個小朋友,是下發。給3個才叫分發。很明顯,事件最終是一我的處理。只是看看給誰而已。
直譯不少狀況下,都會發生意思誤差。
觸摸設計的推導假設android
從直接觸碰的控件往上傳播全部事件,包括down和move,up。
這樣同一個枝的控件均可以知道全部事件。設置一個listener就能夠工做。
設置一個字段,isHandle,是否掌控。一但爲真,那麼就再也不往上傳。
這個設計很簡單,從下往上符合人的感知和經驗。
隨時能夠觸發本身的動做。觸發了本身的,設置下ishandle.
爲何這麼簡單的流程不用。要搞的這麼複雜?
由於有特例要要上層截斷,因此纔有截斷判斷,還能夠設置截斷條件。
截斷又搭配一個ontouch,放在listener.touch以後,比較符合常理。
又想優化下每次事件的傳播效率,纔有down做爲判斷消費者的設計。沒必要要每次都傳到最底層。
截斷後,又想要特例,全部又有了 disallow.
觸摸事件的僞代碼
首先<<android 開發藝術探索>>和網上的僞代碼是同樣的,估計你們都是抄書的,可是我的感受有很是明顯的失誤。都是一抄全錯。 書上的僞代碼,看來是down的僞代碼,可是尾遞歸以後又少一個很重要的,兜底處理。 本身理解的僞代碼,分爲down和其餘事件。由於差異挺大,分爲2個部分更容易理解。
down 僞代碼windows
down event public boolean dispatchTouchEvent(MotionEvent ev) { boolean consume = false; if (onInterceptTouchEvent(ev)) { consume = TouchListener.onTouch(ev)->this.onTouchEvent(ev)->ClickListener.onClick(ev); } else { consume = child.dispatchTouchEvent (ev) ; if(consume==false) { consume = TouchListener.onTouch(ev)->this.onTouchEvent(ev)->ClickListener.onClick(ev); } } return consume; }
move:僞代碼app
public boolean dispatchTouchEvent(MotionEvent ev) { boolean consume = false; if (target==null)//沒有下發目標,本身處理. 有2種狀況 1.最先截斷過down. 2.上次截斷過move { consume = TouchListener.onTouch(ev)->this.onTouchEvent(ev)->ClickListener.onClick(ev); } else { if (onInterceptTouchEvent(ev)) { ev=cancel; consume = child.dispatchTouchEvent (ev) ; target=null; } else { consume = child.dispatchTouchEvent (ev) ; } } return consume; }
詳細流程圖,ide
分爲down事件和非down事件。函數
down 事件佈局
非down事件優化
典型事件圖this
分析過程spa
一。本身的總結。 從大的說,其實就是一個遞歸。
1.down的目的就是找到誰來處理事件,循環全部子控件,一直往下(dispatchTouchEvent)問(onintercepevent),只要有控件截斷,那麼以後全部事件的終點站就是它了。
都不處理,那麼遞歸出來時再沿往回問(touchListener + clickListener)。這樣,經過down事件找到了誰來處理,
2.那麼其餘事件就不須要循環全部子控件了,直接走處理鏈的那一條路(dispatchTouchEvent),一直到目標,調用它的touchListener + clickListener
中途,有截斷的話,那麼就把處理者由原處理者更改成截斷者。特殊狀況down的時候發現沒有處理的view,那麼交給activity處理。
3.調用touchListener + clickListener,通常說成Listener.Ontouch 和 onTouchEvent. 由於onTouchEvent的基類實現就是調用view.onclick.咱們重寫onTouchEvent就是覆蓋view.onclick
細緻點就是先 touchlistener,若是返回flase,再onclickListener.
網上都是任務下派來做爲比喻,很好。只不過大部分沒有詳細點明一些細節。本身詳細比喻下。
假如某公司有多級部門。總公司中心處是activity。activity 總公司中心處 不記住任何東西。只派發任務,並處理你們都不處理的任務。而group會存儲是否有個人分部門處理這件事。而分部分又會記載分分部分。直到分分分分分記錄了某我的。
從總公司中心處,派發任務,當派發了某個任務,這裏就比喻爲點擊了某處。那麼就把這個任務給相關部門,此部門,一層一層的下放到最小的部門的某我的。 固然若是是好差事,中間會有截取。
若是下放到某我的,或者被中間某人截取,可是他後來才發現他沒有能力處理(也就是某個控件,觸摸事件點到它了,可是它沒有消費down)。那麼就一層一層沿來路往上,看看誰能處理。
這裏就比喻 down下發時候的ontouchEvent都返回false的迴歸邏輯。最終有人處理,或者真的無人處理。這裏
ontouchEvent包括咱們的click和自定義的ontoucheventlister。down返回了true。那麼和截斷同樣。就肯定了處理人。下次會逐層傳遞到這裏爲止,也就是仍是會從上往下詢問是否須要中斷,可是不會再像down同樣往回問處不處理。由於已經有人處理了。
以後若是有這個任務的後續處理事件,就比喻爲move,up事件。 那麼仍是從總公司中心處,一層一層過來(不少文章都是說交給某人處理,沒有強調是從上往下一層一層的),直到交給處理這個任務的人,就再也不往下了。
這裏就是比喻其餘事件,也是遞歸進去,並比較是不是當初存儲的那個處理的view。是,就中止遞歸。
固然中間也能夠再截取這個任務,而後再一層一層的通知原來處理這個事情的人,這個任務做廢了。也就是比喻爲中間截取了move或up信號,並一層一層發送cancel事件到down處理者。只發送一次cancel。之後截取的view就成爲了新的處理者,截斷全部事件。
若是當初是無人處理。那麼後續事項,總公司中心處,仍是須要先發給大部門,大部門知道沒法處理。就直接說沒法處理。總公司才本身處理。Activity是不存儲誰處理事情的,只有group才存儲。因此就算沒有處理。activity仍是要先問下頂級group。
最佳實踐
0,沒有額外事件,只有通常的按鈕的點擊。
通常最簡單咱們都是處理點擊事件,按鈕事件。因此基本上不用任何處理。添加點擊事件就ok了。由於group默認是不截斷任何事件的。
一旦咱們須要group也響應觸摸事件,那麼就須要額外處理了
1,只有一個額外事件,並且是按標準來,觸碰到了控件自己才觸發。
若是當前頁面只須要額外添加響應一個事件。那麼咱們最簡單的處理就是給要響應的group控件,添加上onTouchListener。由於事件只有咱們處理,其餘控件都不會處理。那麼最後只要事件是落在咱們控件範圍內,
不須要截斷(onintercept),也會調用咱們的ontouchlistener.ontouch,
2.多個控件分別需求彼此不一樣的事件
若是當前頁面有多個事件,那麼從結果導向的思惟出發,咱們必須讓全部想捕獲動做的group們,都得到事件,因此必須讓中途的group對於down事件無條件放行。 最後一個group最好也放行down,由於只要設置了listener就至關於截斷了down。
這樣以後全部事件都會通過咱們的多個group的dispatchevent直到最後一個group, 這個時候每一個控件,都在onInterceptEvent 中判斷用戶的手指是否已經作出了本身想要的動做,若是是,那麼在返回true。消費事件。 事件處理者從最後一個group,變成了截斷的group。
這樣以後全部事件都會通過咱們的多個group的dispatchevent直到最新的消費者。通常這個時候也會持續接受直到up事件。
這樣從總體看,用戶的動做一旦匹配某個動做,那麼立馬到了對應事件的控件上,其餘的拋棄。這樣就符合人的常識和理解。
3.對於同一個額外事件有多個控件須要
狀況2,是處理多個控件須要不一樣的事件,因此各自寫本身的事件,不會有衝突,若是2個控件都須要滑動呢?那麼按照設置會是控件樹的上層觸發,下層觸發不了。也是一個規則吧,
可是若是真要2個控件都觸發呢,在誰範圍內,誰就觸發,而不是上層把同一個事件,強制截斷了, 這樣要靠diaallowintercept的flag了。下層強制要求,一樣的事件,在我身上,你就不要觸發了,給我,
從上面的邏輯看,是一個完整的邏輯,理論上是沒有遺漏的。
4.我的感受,若是固定的頁面,之後改動不多,事件直接給activity,讓他全局規劃,其實挺好的。
5.要注意分辨,onIntercept,通常對於down放行,由於頁面要處理多事件。 而在ontouch, onclick. touch.中對於down,都是必須消費的。
要區分,截斷和消費是2個概念。 有符合的動做,才須要截斷,可是一旦進入消費函數,說明是從截取過來的,必需要消費down,才能說我要處理這個動做,不消費down。就代表白白截取。
案例分析
1.同方向的2個scrollview的衝突。
由於outer層的scroll截取了滑動事件,因此它會下發一個cancel給inner,致使inner接收不到滑動。
若是scroll裏面是不一樣方向的滑動。那麼正常,可是是同方向,因此不正常,應該是inner處理滑動。outer要放行。因此必須是inner須要的時候,inner纔去通知outer,其餘時候仍是outer處理
11-06 12:55:13.090 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [dispatchTouchEvent]. Line:75 : MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=509.0, y[0]=1705.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902866, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.091 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [onInterceptTouchEvent]. Line:83 : false...MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=509.0, y[0]=1705.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902866, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.092 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXInner [dispatchTouchEvent]. Line:44 : MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=485.0, y[0]=259.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902866, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.093 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXInner [onInterceptTouchEvent]. Line:52 : false...MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=485.0, y[0]=259.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902866, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.093 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXInner [onTouchEvent]. Line:60 : true...MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=485.0, y[0]=259.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902866, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.179 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [dispatchTouchEvent]. Line:75 : MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=539.0663, y[0]=1649.6593, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=150902951, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.179 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [onInterceptTouchEvent]. Line:83 : true...MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=539.0663, y[0]=1649.6593, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=150902951, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.180 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXInner [dispatchTouchEvent]. Line:44 : MotionEvent { action=ACTION_CANCEL, actionButton=0, id[0]=0, x[0]=539.0663, y[0]=1649.6593, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=150902951, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.180 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXInner [onTouchEvent]. Line:60 : true...MotionEvent { action=ACTION_CANCEL, actionButton=0, id[0]=0, x[0]=539.0663, y[0]=1649.6593, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=2, eventTime=150902951, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.196 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [dispatchTouchEvent]. Line:75 : MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=565.0, y[0]=1600.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902964, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.197 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [onTouchEvent]. Line:91 : true...MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=565.0, y[0]=1600.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902964, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.198 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [dispatchTouchEvent]. Line:75 : MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=565.0, y[0]=1600.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902972, downTime=150902866, deviceId=2, source=0x1002 } 11-06 12:55:13.198 27255-27255/com.linson.android.hiandroid2 I/MYCUSTOM~!@: SameDirection$ScrollViewEXOunter [onTouchEvent]. Line:91 : true...MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=565.0, y[0]=1600.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=150902972, downTime=150902866, deviceId=2, source=0x1002 }
只須要在inner 修改
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
{
if(ev.getAction()==MotionEvent.ACTION_DOWN)
{
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
修改以後的日誌
能夠看到 上層再也不進行onInterceptTouchevent了。相似一個返回false的效果。這樣inner就能夠獲得滑動了。
11-06 15:32:43.546 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXOunter [dispatchTouchEvent]. Line:21 : MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=495.0, y[0]=1582.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=159005037, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.548 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXOunter [onInterceptTouchEvent]. Line:29 : false...MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=495.0, y[0]=1582.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=159005037, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.548 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXInner [dispatchTouchEvent]. Line:21 : MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=495.0, y[0]=82.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=159005037, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.549 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXInner [onInterceptTouchEvent]. Line:29 : false...MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=495.0, y[0]=82.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=159005037, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.549 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXInner [onTouchEvent]. Line:37 : true...MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=495.0, y[0]=82.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=159005037, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.578 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXOunter [dispatchTouchEvent]. Line:21 : MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=495.0, y[0]=1596.9578, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=159005066, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.578 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXInner [dispatchTouchEvent]. Line:21 : MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=495.0, y[0]=96.95776, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=159005066, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.579 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXInner [onTouchEvent]. Line:37 : true...MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=495.0, y[0]=96.95776, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=159005066, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.594 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXOunter [dispatchTouchEvent]. Line:21 : MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=491.1193, y[0]=1636.6948, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=159005082, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.595 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXInner [dispatchTouchEvent]. Line:21 : MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=491.1193, y[0]=136.69482, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=1, eventTime=159005082, downTime=159005037, deviceId=2, source=0x1002 }
11-06 15:32:43.596 3461-3461/com.linson.android.hiandroid2 I/MYCUSTOM~!@: ScrollViewEXInner [onTouchEvent]. Line:37 : true...MotionEvent { action=ACTION_MOVE, actionButton=0
未解決的疑點
1.當有匹配的事件發生,只給下面說你的事件取消了,可是不告訴本身去觸發事件? 這樣不是浪費了一個事件了不?雖然不少狀況下是可有可無,可是邏輯上仍是錯誤啊。萬一下一個事件就是up事件呢?因此截取必定不能截取up?不然不會觸發本身的touch事件!!!
解決:en .能夠在onintercept,設置一個變量,來告訴事情已經發生了。若是最後一個是up。那麼就直接觸發動做。不須要touch事件。不然,根據定義好的變量,在touch中直接作動做,後面的事件直接消費就行了,不做爲事件是否發生的標誌。
2.若是截斷後產生了新的事件消費者控件,事件都已經觸發了,假設它上層某個控件有個事件,又匹配上了用戶的後續動做呢?,又要截斷? 那要觸發2個動做。不符合人的常識啊。
解決:能夠在截斷後,設置 disallow爲true。這樣保證上層不會再截止動做了。只有咱們本身一個動做執行者。
補充 activity ,window, dector的處理分析
C:\android\sdk\sources\android-28\android\app\activity.java /** * Called to process touch screen events. You can override this to * intercept all touch screen events before they are dispatched to the * window. Be sure to call this implementation for touch screen events * that should be handled normally. * * @param ev The touch screen event. * * @return boolean Return true if this event was consumed. */ public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } else { return onTouchEvent(ev); } } private Window mWindow; public Window getWindow() { return mWindow; } mWindow = new PhoneWindow(this, window, activityConfigCallback); C:\android\sdk\sources\android-28\android\view\window.java /** * Used by custom windows, such as Dialog, to pass the touch screen event * further down the view hierarchy. Application developers should * not need to implement or call this. * */ public abstract boolean superDispatchTouchEvent(MotionEvent event); C:\android\sdk\sources\android-28\com\android\internal\policy\PhoneWindow.java @Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); } mDecor = (DecorView) preservedWindow.getDecorView(); mDecor = generateDecor(-1); DecorView就是Window的頂級View,它派生於FrameLayout,而FrameLayout又派生於groupview。因此咱們能夠最後追到ViewGroup.java 因此最終看ViewGroup.java的dispatchTouchEvent就能夠。可是須要配合下面這幅圖。其中contentViews是咱們的佈局xml文件的內容。
C:\android\sdk\sources\android-28\com\android\internal\policy\DecorView.java public boolean superDispatchTouchEvent(MotionEvent event) { return super.dispatchTouchEvent(event); }