Webview&Viewpager滑動沖突解決方案

參考的文章

感謝這些作者的分享

http://www.reibang.com/p/24038d957e93
https://developer.android.com/jetpack/androidx/releases/swiperefreshlayout
https://wangyeming.github.io/2017/07/16/use-webview-in-viewpager/

在使用viewpager時(shí)棺滞,如果某一頁存在webview,則會出現(xiàn)webview中輪播圖或者其他滑動控件,無法滑動的問題。這種情況是可以僅通過app端就解決的亮元。

解決問題的思路

1担平、如何控制使用webview處理事件還是viewpager處理事件。
2戈轿、根據(jù)什么來判斷webview處理事件還是viewpager處理事件症副。

問題一:如何控制

所有的滑動沖突問題解決的思路就是兩個(gè):

  • 內(nèi)部攔截法
  • 外部攔截法

在這個(gè)場景中店雅,在webview外面,可能還包了fragment等眾多viewgroup贞铣,并且最終判斷誰處理事件的依據(jù)在webview中闹啦,所以這里使用內(nèi)部攔截法更方便。

public class ScrollConflictWebView extends WebView {

    private boolean 判斷依據(jù) = false;

    public ScrollConflictWebView(Context context) {
        super(context);
    }

    public ScrollConflictWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    判斷依據(jù) = false;
                                        //Down時(shí)攔截事件保證在move時(shí)可以拿到事件辕坝。
                    requestDisallowInterceptTouchEvent(true);
                    break;
                case MotionEvent.ACTION_MOVE:
                    //Move時(shí)決定是否還要攔截事件
                    requestDisallowInterceptTouchEvent(!判斷依據(jù));
                    break;
                default:
                    requestDisallowInterceptTouchEvent(false);
                                        break;
            }
             return super.onTouchEvent(event);
    }

}

可能你在測試時(shí)窍奋,會出現(xiàn)無法攔截的情況,我也遇到了酱畅,因?yàn)槭褂昧薙wipeRefreshLayout琳袄。下文會說到。

問題2:如何判斷

我找到了兩種思路纺酸,第一種

  • 通過js交互實(shí)現(xiàn)窖逗,h5告訴客戶端什么情況下是可以滑動的,或者什么位置是可以滑動的餐蔬。
  • 通過webview自身的回調(diào):onOverScrolled來判斷碎紊。參考了這個(gè)文章

顯然,第一種方法是非常麻煩的樊诺,涉及到j(luò)s交互仗考,不具備通用性。因?yàn)闇y試了uc和夸克词爬,發(fā)現(xiàn)在他們的瀏覽器中秃嗜,都自動解決了滑動沖突,所以必然是有其他可以判斷的依據(jù)的缸夹,最終找到了第二種方法痪寻。

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        isScrollX = clampedX;
    }

這個(gè)方法觸發(fā)的時(shí)機(jī)是webview滑動到邊界時(shí)會觸發(fā)螺句,如果是橫向滑動虽惭,則clamped則為true。這樣的話蛇尚,我們只要在clamped為true的時(shí)候芽唇,把事件交給viewpager來處理就行了。

public class ScrollConflictWebView extends WebView {

    private boolean 判斷依據(jù) = false;

    public ScrollConflictWebView(Context context) {
        super(context);
    }

    public ScrollConflictWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    判斷依據(jù) = false;
                                        //Down時(shí)攔截事件保證在move時(shí)可以拿到事件。
                    requestDisallowInterceptTouchEvent(true);
                    break;
                case MotionEvent.ACTION_MOVE:
                    //Move時(shí)決定是否還要攔截事件
                    requestDisallowInterceptTouchEvent(!判斷依據(jù));
                    break;
                default:
                    requestDisallowInterceptTouchEvent(false);
                                        break;
            }
             return super.onTouchEvent(event);
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        判斷依據(jù) = clampedX;
    }

}

上面說到了匆笤,如果你Webview的父布局中存在SwipeRefreshLayout研侣,會發(fā)現(xiàn),可能disallow無法傳遞到viewpager炮捧。理論上庶诡,不做任何處理,viewgroup的disallow方法咆课,會挨個(gè)往父布局傳遞末誓。但是為什么會傳遞失敗呢?這就得看下SwipeRefreshLayout的源碼(appcompat版本:1.2.0-alpha03)了:

@Override
public void requestDisallowInterceptTouchEvent(boolean b) {
    // if this is a List < L or another view that doesn't support nested
    // scrolling, ignore this request so that the vertical scroll event
    // isn't stolen
    if ((android.os.Build.VERSION.SDK_INT < 21 && mTarget instanceof AbsListView)
            || (mTarget != null && !ViewCompat.isNestedScrollingEnabled(mTarget))) {
        // Nope.
    } else {
        super.requestDisallowInterceptTouchEvent(b);
    }
}

從源碼可以看出书蚪,如果SwipeRefreshLayout包裹的布局不支持NestedScroll的話喇澡,就不做任何處理。
其實(shí)這個(gè)是appcompat在1.2.0中才修改的殊校,1.1.0版本是給了方法自己控制的:


image.png

一開始的思路是讓SwipeRefreshLayout下面一層View支持nestedScroll晴玖,但是這樣的話,會導(dǎo)致下拉刷新無法觸發(fā)为流。
那就只能手動去修改disallow方法了:

public class AllowSwipeRefreshLayout extends QFSwipeRefreshLayout {
    public AllowSwipeRefreshLayout(@NonNull @NotNull Context context) {
        super(context, null);
    }

    public AllowSwipeRefreshLayout(@NonNull @NotNull Context context, @Nullable @org.jetbrains.annotations.Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void requestDisallowInterceptTouchEvent(boolean b) {
        getParent().requestDisallowInterceptTouchEvent(b);
        super.requestDisallowInterceptTouchEvent(b);
    }
}

這樣修改以后呕屎,disallow就可以正常傳遞給viewpager了。到這里敬察,就完美的解決了webview嵌套在Viewpager中的滑動沖突問題榨惰。
最終實(shí)現(xiàn)效果與uc和夸克一致。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末静汤,一起剝皮案震驚了整個(gè)濱河市琅催,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌虫给,老刑警劉巖藤抡,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異抹估,居然都是意外死亡缠黍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門药蜻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓷式,“玉大人,你說我怎么就攤上這事语泽∶车洌” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵踱卵,是天一觀的道長廊驼。 經(jīng)常有香客問我据过,道長,這世上最難降的妖魔是什么妒挎? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任绳锅,我火速辦了婚禮,結(jié)果婚禮上酝掩,老公的妹妹穿的比我還像新娘鳞芙。我一直安慰自己,他們只是感情好期虾,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布积蜻。 她就那樣靜靜地躺著,像睡著了一般彻消。 火紅的嫁衣襯著肌膚如雪竿拆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天宾尚,我揣著相機(jī)與錄音丙笋,去河邊找鬼。 笑死煌贴,一個(gè)胖子當(dāng)著我的面吹牛御板,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牛郑,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼怠肋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淹朋?” 一聲冷哼從身側(cè)響起笙各,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎础芍,沒想到半個(gè)月后杈抢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仑性,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年惶楼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诊杆。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歼捐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晨汹,到底是詐尸還是另有隱情豹储,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布宰缤,位于F島的核電站颂翼,受9級特大地震影響晃洒,放射性物質(zhì)發(fā)生泄漏慨灭。R本人自食惡果不足惜朦乏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氧骤。 院中可真熱鬧呻疹,春花似錦、人聲如沸筹陵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朦佩。三九已至并思,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間语稠,已是汗流浹背宋彼。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仙畦,地道東北人输涕。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像慨畸,于是被迫代替她去往敵國和親莱坎。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

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