前言:滑動沖突是如何產(chǎn)生的呢觉痛?其實在界面中只要內(nèi)外兩層同時可以滑動君旦,這個時候就會產(chǎn)生滑動沖突贡蓖。如何解決滑動沖突呢甩牺?滑動沖突的解決有固定的套路蘑志,只要知道了這個固定套路問題就好解決了。
一:常見的滑動沖突場景
場景1:外部滑動方向和內(nèi)部滑動方向不一致贬派;
主要是將ViewPager和Fragment配合使用所組成的頁面滑動效果急但,主流應(yīng)用幾乎都會使用這個效果。在這個效果中搞乏,可以通過左右滑動來切換頁面波桩,而每個頁面內(nèi)部往往又是一個ListView。本來這種情況下是有滑動沖突的请敦,但是ViewPager內(nèi)部處理了這種滑動沖突镐躲,因此采用ViewPager時我們無須關(guān)注這個問題,如果我們采用的不是ViewPager而是ScrollView等侍筛,那就必須手動處理滑動沖突了萤皂,否則造成的后果就是內(nèi)外兩層只能一層能夠滑動,這是因為兩者之間的滑動事件有沖突匣椰。除了這種典型情況外裆熙,還存在其他的情況,比如外部上下滑動,內(nèi)部左右滑動等窝爪,但是它們屬于同一類滑動沖突弛车。
場景2:外部滑動方向和內(nèi)部滑動方向一致;
場景3:上面兩種情況的嵌套蒲每。
二:滑動沖突的處理規(guī)則
對于場景1,它的處理規(guī)則是:當(dāng)用戶左右滑動時喻括,需要讓外部的View攔截點擊事件邀杏,當(dāng)用戶上下滑動時,需要讓內(nèi)部View攔截點擊事件。這個時候我們就可以根據(jù)它們的特征來解決滑動沖突望蜡,具體來說是:根據(jù)滑動是水平滑動還是數(shù)值滑動來判斷到底有誰來攔截事件唤崭,根據(jù)滑動過程中兩點之間的坐標(biāo)就可以得出到底是水平滑動還是豎直滑動。如何根據(jù)坐標(biāo)來得到滑動的方向呢脖律?可以依據(jù)滑動路徑和水平方向所形成的夾角谢肾,也可以依據(jù)水平方向和豎直上的距離差來判斷,某些特殊時候還可以依據(jù)水平和豎直方向的速度差來判斷小泉。
場景2芦疏,3都是從業(yè)務(wù)的需求上得出相應(yīng)的處理規(guī)則。
三微姊、滑動沖突的解決方式
針對滑動沖突酸茴,這里給出兩種解決滑動沖突的方式:外部攔截法和內(nèi)部攔截法。
1.外部攔截法
所謂外部攔截法是指點擊事情都先經(jīng)過父容器的攔截處理兢交,如果父容器需要此事件就攔截薪捍,如果不需要此事件就不攔截,這樣就可以解決滑動沖突的問題配喳,這種方法比較符合點擊事件的分發(fā)機(jī)制酪穿。外部攔截法需要重寫父容器的onInterceptTouchEvent方法,在內(nèi)部做相應(yīng)的攔截即可晴裹。在onInterceptTouchEvent方法中昆稿,首先是ACTION_DOWN這個事件,父容器必須返回false息拜,即不攔截ACTION_DOWN事件溉潭,這是因為一旦父容器攔截了ACTION_DOWN,那么后續(xù)的ACTION_MOVE和ACTION_UP事件都會直接交由父容器處理少欺,這個時候事件沒法再傳遞給子元素了喳瓣;其次是ACTION_MOVE事件,這個事件可以根據(jù)需要來決定是否攔截赞别,如果父容器需要攔截就返回true畏陕,否則返回false;最后是ACTION_UP事件仿滔,這里必須要返回false惠毁,因為ACTION_UP事件本身沒有太多意義考慮一種情況,假設(shè)事件交由子元素處理崎页,如果父容器在ACTION_UP時返回了true鞠绰,會導(dǎo)致子元素?zé)o法接收到ACTION_UP事件,這個時候子元素中的onClick事件就無法觸發(fā)飒焦,但是父容器比較特殊蜈膨,一旦它開始攔截任何一個事件,那么后續(xù)的事件都會交給它處理,而ACTION_UP作為最后一個事件也必定可以傳遞給父容器翁巍,即便父容器的onInterceptTouchEvent方法在ACTION_UP時返回了false驴一。
2.內(nèi)部攔截法
內(nèi)部攔截法是指父容器不攔截任何事件,所有的事件都傳遞給子元素灶壶,如果子元素要消耗此事件就直接消耗掉肝断,否則就交由父容器進(jìn)行處理,這種方法和Android中的事件分發(fā)機(jī)制不一致驰凛,需要配合requestDisallowInterceptTouchEvent方法才能正常工作胸懈,使用起來較外部攔截法稍顯復(fù)雜。它的偽代碼如下洒嗤,我們需要重寫子元素的dispatchTouchEvent方法:
上述代碼就是內(nèi)部攔截法的典型代碼箫荡,當(dāng)面對不同的滑動策略只需要修改里面的條件即可,其他不需要做改動渔隶,除了子元素需要處理之外羔挡,父元素默認(rèn)也要攔截除ACTION_DOWN之外的其他事件,這樣當(dāng)子元素調(diào)用getParent().requestDisallowInterceptTouchEvent(true)方法時间唉,父元素才能繼續(xù)攔截所需要的事件绞灼。為什么父容器不能攔截ACTION_DOWN事件呢?那是因為ACTION_DOWN事件并不接受FLAG_DISALLOW_DOWN這個標(biāo)記位的控制呈野,所以一旦父容器攔截低矮,那么所有的事件都無法傳遞到子元素中,這樣額你不攔截就無法起作用了被冒,父元素要做的如下修改军掂。
因為內(nèi)部攔截法沒有外部攔截法簡單易用,所以推薦采用外部攔截法來解決常見的滑動沖突昨悼。
參考鏈接:https://blog.csdn.net/qq_26787115/article/details/53047914