View事件體系 -- 滑動沖突

一敷硅、概念

在界面中只要內(nèi)外兩層同時可以滑動,這個時候就會產(chǎn)生滑動沖突旁赊。

二桦踊、沖突場景

場景1:外部滑動方向和內(nèi)部滑動方向不一致
外部左右滑動、內(nèi)部上下滑動终畅;
外部上下滑動籍胯,內(nèi)部左右滑動。
例子:ViewPager + ListView
將ViewPager和Fragment配合使用組成頁面滑動效果离福,可以通過左右滑動來切換頁面杖狼,而每個頁面內(nèi)部往往又是一個ListView,可以上下滑動妖爷。本來這種情況是有滑動沖突的蝶涩,但是ViewPager內(nèi)部處理了這種滑動沖突,因此采用ViewPager時我們無須關(guān)注這個問題絮识。如果我們采用的不是ViewPager而是ScrollView等绿聘,那就必須手動處理滑動沖突了,否則會造成內(nèi)外兩層只能有一層能夠滑動次舌。
場景2:外部滑動方向和內(nèi)部滑動方向一致
外部左右滑動熄攘、內(nèi)部左右滑動;
外部上下滑動垃它,內(nèi)部上下滑動鲜屏。
場景3:場景1和場景2兩種情況的嵌套
例子:SlideMenu + ViewPager + ListView
外部有一個SlideMenu左右滑動效果烹看,內(nèi)部有一個ViewPager左右滑動效果,ViewPager的每一個頁面中又是一個ListView上下滑動效果洛史。雖然場景3看起來更復雜惯殊,但是它是幾個單一的滑動沖突的疊加,因此只需要分別處理內(nèi)層和中層也殖、中層和外層之間的滑動沖突即可土思。

三、處理規(guī)則

場景1:
根據(jù)滑動是水平滑動還是豎直滑動來判斷到底由誰來攔截事件忆嗜〖喝澹可以根據(jù)滑動的角度、距離差以及速度差來確定滑動方向捆毫。
例子中闪湾,當用戶左右滑動的時候,需要讓外部的View攔截點擊事件绩卤,當用戶上下滑動的時候途样,需要讓內(nèi)部View攔截點擊事件。
場景2:
在業(yè)務上找到突破點濒憋。比如業(yè)務上有規(guī)定:當處于某種狀態(tài)時需要外部View響應用戶的滑動何暇,而處于另外一種狀態(tài)時則需要內(nèi)部View來響應View的滑動。
場景3:
同場景2一樣凛驮,只能在業(yè)務上找到突破點裆站。

四、滑動沖突的解決方式

1.外部攔截法(推薦)
外部攔截法是指點擊事件先經(jīng)過父容器的攔截處理黔夭,如果父容器需要此事件就攔截宏胯,如果不需要此事件就不攔截,這樣就可以解決滑動沖突問題纠修,這種方法比較符合點擊事件的分發(fā)機制胳嘲。外部攔截法需要重寫父容器的onInterceptTouchEvent方法厂僧,在內(nèi)部做相應的攔截即可扣草。
偽代碼如下:

//重寫父容器的onInterceptTouchEvent方法
public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int)event.getX();
    int y = (int)event.getY();
    switch(event.getAction()) {
    case MotionEvent.ACTION_DOWN: //按下事件不攔截
        intercepted = false;
        break;
    case MotionEvent.ACTION_MOVE: //滑動事件根據(jù)需要攔截
        if(父容器需要當前點擊事件) {
            intercepted = true;
        } else {
            intercepted = false;
        }
        break;
    case MotionEvent.ACTION_UP: //松開事件不攔截
        intercepted = false;
        break;
    default:
        break;
    }
    return intercepted;
}

2.內(nèi)部攔截法
內(nèi)部攔截法是指父容器不攔截任何事件,所有的事件都傳遞給子元素颜屠,如果子元素需要此事件就直接消耗掉辰妙,否則就交給父容器進行處理,這種方法和事件分發(fā)機制不一致甫窟,需要配合ViewGroup#requestDisallowInterceptTouchEvent方法才能正常工作密浑。
偽代碼如下:

//重寫子元素的dispatchTouchEvent方法
public boolean dispatchTouchEvent(MotionEvent event) {
    int x = (int)event.getX();
    int y = (int)event.getY();
    switch(event.getAction()) {
    case MotionEvent.ACTION_DOWN: 
        parent.requestDisallowInterceptTouchEvent(true);
        break;
    case MotionEvent.ACTION_MOVE: 
        int deltaX = x - mLastX;
        int deltaY = y - mLastY;
        if(父容器需要當前點擊事件) {
            parent.requestDisallowInterceptTouchEvent(false);
        }
        break;
    case MotionEvent.ACTION_UP: 
        break;
    default:
        break;
    }
    mLastX = x;
    mLastY = y;
    return super.dispatchTouchEvent(event);
}

//重寫父容器的onInterceptTouchEvent方法
public boolean onInterceptTouchEvent(MotionEvent event) {
    int action = event.getAction();
    if(action == MotionEvent.ACTION_DOWN) {
        return false;
    } else {
        return true;
    }
}

五、實例

問題:
App使用ViewPager + TabLayout + Fragment框架粗井,其中一個fragment的內(nèi)容是只有一個自定義的webview控件尔破,進行加載H5頁面街图,H5頁面上有一個水平方向上的圖片輪播控件,當水平滑動該圖片輪播控件時會出現(xiàn)App切換Tab現(xiàn)象懒构,即外層ViewPager控件攔截了該滑動事件餐济,導致內(nèi)層H5頁面的圖片輪播控件無法在手動滑動的情況下正常切換圖片。

方案:
當手指接觸到H5頁面的圖片輪播控件區(qū)域時胆剧,由JS調(diào)用native的接口設置一個標志位為true絮姆,表示當前的觸摸事件需要交給webview來處理,在webview的事件處理方法onTouchEvent中秩霍,在該標志位為true的前提下篙悯,如果當前是ACTION_DOWN事件,則調(diào)用父容器的requestDisallowInterceptTouchEvent(true)方法不允許父容器攔截事件铃绒,如果當前是ACTION_UP或者ACTION_CANCEL事件鸽照,則調(diào)用父容器的requestDisallowInterceptTouchEvent(false)方法允許父容器攔截事件,并將該標志位設置為false颠悬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末移宅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子椿疗,更是在濱河造成了極大的恐慌漏峰,老刑警劉巖屑墨,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砾嫉,死亡現(xiàn)場離奇詭異,居然都是意外死亡礁竞,警方通過查閱死者的電腦和手機铝条,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門靖苇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人班缰,你說我怎么就攤上這事贤壁。” “怎么了埠忘?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵脾拆,是天一觀的道長。 經(jīng)常有香客問我莹妒,道長名船,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任旨怠,我火速辦了婚禮渠驼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鉴腻。我一直安慰自己迷扇,他們只是感情好百揭,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜓席,像睡著了一般信峻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瓮床,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天盹舞,我揣著相機與錄音,去河邊找鬼隘庄。 笑死踢步,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的丑掺。 我是一名探鬼主播获印,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼街州!你這毒婦竟也來了兼丰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤唆缴,失蹤者是張志新(化名)和其女友劉穎鳍征,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體面徽,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡艳丛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了趟紊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氮双。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖霎匈,靈堂內(nèi)的尸體忽然破棺而出戴差,到底是詐尸還是另有隱情,我是刑警寧澤铛嘱,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布暖释,位于F島的核電站,受9級特大地震影響弄痹,放射性物質(zhì)發(fā)生泄漏饭入。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一肛真、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爽航,春花似錦蚓让、人聲如沸乾忱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窄瘟。三九已至,卻和暖如春趟卸,著一層夾襖步出監(jiān)牢的瞬間蹄葱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工锄列, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留图云,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓邻邮,卻偏偏與公主長得像竣况,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筒严,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容