3.Android View滑動沖突的完美解決方案 上百次項目實踐沉淀 RecyclewView各種滑動沖突解決


面試五連環(huán)

1.滑動沖突的幾種情況

2.滑動沖突解決方案和源碼分析

3.滑動沖突的幾種解決方案的使用場景?什么時候用內部攔截稳摄?

4.webview滑動沖突如何解決?x5 webview如何攔截撵枢?

5.滑動沖突實踐

1.滑動沖突的幾種情況

1).點擊時間和滑動事件(比如懸浮球)

2).外層與內層滑動方向不一致锋喜,外層ViewGroup是可以橫向滑動的,內層View是可以豎向滑動的(類似ViewPager棒搜,每個頁面里面是ListView)

3).外層與內層滑動方向一致疹蛉,外層ViewGroup是可以豎向滑動的,內層View同樣也是豎向滑動的(類似ScrollView包裹ListView)

2.滑動沖突解決方案和源碼分析

針對上面第一種場景力麸,onTouch和onTouchEvent事件可款,即可

針對上面第二種場景,由于外部與內部的滑動方向不一致克蚂,那么我們可以根據(jù)當前滑動方向闺鲸,水平還是垂直來判斷這個事件到底該交給誰來處理。至于如何獲得滑動方向埃叭,我們可以得到滑動過程中的兩個點的坐標摸恍。如豎直距離與橫向距離的大小比較;

針對第三種場景赤屋,由于外部與內部的滑動方向一致立镶,那么不能根據(jù)滑動角度壁袄、距離差或者速度差來判斷。這種情況下必需通過業(yè)務邏輯來進行判斷谜慌。比較常見ScrollView嵌套了ListView。

套路一 外部攔截法:

即父View根據(jù)需要對事件進行攔截莺奔。邏輯處理放在父View的onInterceptTouchEvent方法中欣范。我們只需要重寫父View的onInterceptTouchEvent方法,并根據(jù)邏輯需要做相應的攔截即可令哟。

publicbooleanonInterceptTouchEvent(MotionEvent event){booleanintercepted =false;intx = (int) event.getX();inty = (int) event.getY();switch(event.getAction()) {caseMotionEvent.ACTION_DOWN: {? ? ? ? ? ? ? ? intercepted =false;break;? ? ? ? ? ? }caseMotionEvent.ACTION_MOVE: {if(滿足父容器的攔截要求) {? ? ? ? ? ? ? ? ? ? intercepted =true;? ? ? ? ? ? ? ? }else{? ? ? ? ? ? ? ? ? ? intercepted =false;? ? ? ? ? ? ? ? }break;? ? ? ? ? ? }caseMotionEvent.ACTION_UP: {? ? ? ? ? ? ? ? intercepted =false;break;? ? ? ? ? ? }default:break;? ? ? ? }? ? ? ? mLastXIntercept = x;? ? ? ? mLastYIntercept = y;returnintercepted;? ? }

上面?zhèn)未a表示外部攔截法的處理思路恼琼,需要注意下面幾點(down和up一樣不攔截,move根據(jù)條件攔截)

ACTION_DOWN 一定返回false屏富,不要攔截它晴竞,否則根據(jù)View事件分發(fā)機制,后續(xù)ACTION_MOVE 與 ACTION_UP事件都將默認交給父View去處理狠半!

在ACTION_MOVE方法中進行判斷噩死,根據(jù)業(yè)務邏輯需要,如果需要父View處理則返回true神年,否則返回false已维,事件分發(fā)給子View去處理。

原則上ACTION_UP也需要返回false已日,如果返回true垛耳,并且滑動事件交給子View處理,那么子View將接收不到ACTION_UP事件飘千,子View的onClick事件也無法觸發(fā)堂鲜。而父View不一樣,如果父View在ACTION_MOVE中開始攔截事件护奈,那么后續(xù)ACTION_UP也將默認交給父View處理缔莲!

套路二 內部攔截法:

即父View不攔截任何事件,所有事件都傳遞給子View霉旗,子View根據(jù)需要決定是自己消費事件還是給父View處理酌予。這需要子View使用requestDisallowInterceptTouchEvent方法才能正常工作。下面是子View的dispatchTouchEvent方法的偽代碼:

父View需要重寫onInterceptTouchEvent方法:

為什么要重寫父類的onInterceptTouchEvent?因為默認不攔截奖慌,你需要的是攔截它

publicbooleanonInterceptTouchEvent(MotionEvent event){intaction = event.getAction();if(action == MotionEvent.ACTION_DOWN) {//down不攔截抛虫,給子類returnfalse;? ? ? ? }else{//攔截returntrue;? ? ? ? }? ? }

重寫子類的dispatchTouchEvent()方法

? public boolean dispatchTouchEvent(MotionEvent event) {intx = (int) event.getX();inty = (int) event.getY();switch(event.getAction()) {caseMotionEvent.ACTION_DOWN: {? ? ? ? ? ? ? ? parent.requestDisallowInterceptTouchEvent(true);break;? ? ? ? ? ? }caseMotionEvent.ACTION_MOVE: {intdeltaX = x - mLastX;intdeltaY = y - mLastY;if(父容器需要此類點擊事件) {? ? ? ? ? ? ? ? ? ? parent.requestDisallowInterceptTouchEvent(false);? ? ? ? ? ? ? ? }break;? ? ? ? ? ? }caseMotionEvent.ACTION_UP: {break;? ? ? ? ? ? }default:break;? ? ? ? }? ? ? ? mLastX = x;? ? ? ? mLastY = y;returnsuper.dispatchTouchEvent(event);? ? }

內部攔截法要求父View不能攔截ACTION_DOWN事件,由于ACTION_DOWN不受FLAG_DISALLOW_INTERCEPT標志位控制简僧,一旦父容器攔截ACTION_DOWN那么所有的事件都不會傳遞給子View建椰。

滑動策略的邏輯放在子View的dispatchTouchEvent方法的ACTION_MOVE中,如果父容器需要獲取點擊事件則調用 parent.requestDisallowInterceptTouchEvent(false)方法岛马,讓父容器去攔截事件棉姐。

?你好屠列,內部攔截法中父容器 onInterceptTouchEvent 方法 ACTION_MOVE、ACTION_UP返回true伞矩,子view 的dispatchTouchEvent 方法中ACTION_MOVE笛洛、ACTION_UP事件還能接受到嗎,新手乃坤,這里不是很懂苛让,求指教?

原理分析:

?? 內部攔截法也叫View分發(fā)反向制約的方法?

?? 攔截不攔截湿诊,由2個東西決定的狱杰。一個是requestDisllowIntercepter和onInterceptTouchEvent()2個決定的。

源碼如下厅须。

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

if (mInputEventConsistencyVerifier !=null) {

mInputEventConsistencyVerifier.onTouchEvent(ev, 1);

? ? }

// If the event targets the accessibility focused view and this is it, start

// normal event dispatch. Maybe a descendant is what will handle the click.

? ? if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {

ev.setTargetAccessibilityFocus(false);

? ? }

if (actionMasked == MotionEvent.ACTION_DOWN

? ? ? ? ||mFirstTouchTarget !=null) {

final boolean disallowIntercept = (mGroupFlags &FLAG_DISALLOW_INTERCEPT) !=0;

? ? if (!disallowIntercept) {

intercepted = onInterceptTouchEvent(ev);

? ? ? ? ev.setAction(action); // restore action in case it was changed

? ? }else {

intercepted =false;

? ? }

原因:但是子元素可以通過requestDisallowInterceptTouchEvent來干預父元素的分發(fā)過程仿畸,但是down事件除外(因為down事件方法里,會清除所有的標志位)朗和。

3.滑動沖突的幾種解決方案的使用場景

1).onTouch和繪制不管错沽。只管事件的攔截和分發(fā),所以重要的方法是:VIewGourp的onInterceptTouchEvent和View的dispatchTouchEvent

2.down眶拉,move ,Up,都是否需要攔截甥捺?

ACTION_DOWN,都不要攔截子類

在這里,首先down事件父容器必須返回false 镀层,因為若是返回true镰禾,也就是攔截了down事件,

那么后續(xù)的move和up事件就都會傳遞給父容器唱逢,子元素就沒有機會處理事件了吴侦。其次是up事件也返回了false,一是因為up事件對父容器沒什么意義坞古,其次是因為若事件是子元素處理的备韧,卻沒有收到up事件會讓子元素的onClick事件無法觸發(fā)。

3.要在MotionEvent.ACTION_MOVE根據(jù)情況痪枫,是父類滑動還是子類滑動

4.2種方式都要重寫父View需要重寫onInterceptTouchEvent方法:

可以看出外部攔截法實現(xiàn)起來更加簡單织堂,而且也符合View的正常事件分發(fā)機制,所以推薦使用外部攔截法(重寫父View的onInterceptTouchEvent奶陈,父View決定是否攔截)來處理滑動沖突

外部攔截下面列子:

1.down 不攔截易阳,否則up收不到,點擊事件也會沒有

2.move 更加業(yè)務判定吃粒。得到子view潦俺,滑動的距離和item的位置決定

3.up? ? ?不攔截

外部攔截法代碼:

@OverridepublicbooleanonInterceptTouchEvent(MotionEventevent){boolean intercepted=false;inty=(int)event.getY();switch(event.getAction()){caseMotionEvent.ACTION_DOWN:{nowY=y;intercepted=super.onInterceptTouchEvent(event);break;}caseMotionEvent.ACTION_MOVE:{if(mListView.getFirstVisiblePosition()==0&&y>nowY){intercepted=true;break;}elseif(mListView.getLastVisiblePosition()==mListView.getCount()-1&&y<nowY){intercepted=true;break;}intercepted=false;break;}caseMotionEvent.ACTION_UP:{intercepted=false;break;}default:break;}returnintercepted;}

什么時候用內部攔截? ? 主要用內部攔截,系統(tǒng)里面的事示,horscorrlview和早像,比如recyleview.

什么時候用外部攔截?? ?主要看你哪個View是你自己的

面試有一個人問道:

一個ScrowView(父類)和一個RecycleView(子類)

他說重寫子類的onIntecepter方法肖爵,讓子類攔截卢鹦,消費掉

5.滑動沖突實踐

實戰(zhàn)案例一:

ListView下拉刷新,需要ListView自身滑動劝堪,

但是當滑動到頭部時需要ListView和Header一起滑動冀自,也就是整個父容器的滑動。如果不處理好滑動沖突幅聘,就會出現(xiàn)各種意想不到情況凡纳。

實戰(zhàn)案例二:

自定義ViewGroup實現(xiàn)瀑布流效果

https://www.cnblogs.com/qhyuan1992/p/5385335.html

實戰(zhàn)案例三:

.ViewPager中嵌套ViewPager怎么處理滑動沖突窃植?

1.重寫canScroll()方法

2.自己手寫

https://blog.csdn.net/weixin_43917449/article/details/86519726

實戰(zhàn)案例四:

一個scorview和一個日期選擇器

自己通過實踐帝蒿,進行重繪寫的

private void doMove(MotionEvent event)

{

mMoveLen += (event.getY() -mLastDownY);

? ? if (mMoveLen >MARGIN_ALPHA *mMinTextSize /2)

{

// 往下滑超過離開距離

? ? ? ? moveTailToHead();

? ? ? ? mMoveLen =mMoveLen -MARGIN_ALPHA *mMinTextSize;

? ? }else if (mMoveLen < -MARGIN_ALPHA *mMinTextSize /2)

{

// 往上滑超過離開距離

? ? ? ? moveHeadToTail();

? ? ? ? mMoveLen =mMoveLen +MARGIN_ALPHA *mMinTextSize;

? ? }

mLastDownY = event.getY();

? ? invalidate();

}

參考:

http://www.reibang.com/p/057832528bdd

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市巷怜,隨后出現(xiàn)的幾起案子葛超,更是在濱河造成了極大的恐慌,老刑警劉巖延塑,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绣张,死亡現(xiàn)場離奇詭異,居然都是意外死亡关带,警方通過查閱死者的電腦和手機侥涵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宋雏,“玉大人芜飘,你說我怎么就攤上這事∧プ埽” “怎么了嗦明?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蚪燕。 經常有香客問我娶牌,道長,這世上最難降的妖魔是什么馆纳? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任诗良,我火速辦了婚禮,結果婚禮上鲁驶,老公的妹妹穿的比我還像新娘累榜。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布壹罚。 她就那樣靜靜地躺著葛作,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猖凛。 梳的紋絲不亂的頭發(fā)上赂蠢,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音辨泳,去河邊找鬼虱岂。 笑死,一個胖子當著我的面吹牛菠红,可吹牛的內容都是我干的第岖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼试溯,長吁一口氣:“原來是場噩夢啊……” “哼蔑滓!你這毒婦竟也來了?” 一聲冷哼從身側響起遇绞,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤键袱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后摹闽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹄咖,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年付鹿,在試婚紗的時候發(fā)現(xiàn)自己被綠了澜汤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡舵匾,死狀恐怖俊抵,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情纽匙,我是刑警寧澤务蝠,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站烛缔,受9級特大地震影響馏段,放射性物質發(fā)生泄漏。R本人自食惡果不足惜践瓷,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一院喜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晕翠,春花似錦喷舀、人聲如沸砍濒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爸邢。三九已至,卻和暖如春拿愧,著一層夾襖步出監(jiān)牢的瞬間杠河,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工浇辜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留券敌,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓柳洋,卻偏偏與公主長得像待诅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子熊镣,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容