问题记录-CoordinatorLayout+WebView使用遇到的问题
阅读原文时间:2023年07月10日阅读:1

需求背景:

使用CoordinatorLayout+viewpager+tablayout+webview实现首页折叠效果。

使用问题:

在使用过程中首页的页面为原生/h5混合页,在原生页面正常,嵌套h5页面头部CollapsingToolbarLayout无法滚动,开始的解决方式是在webview上面嵌套NestedScrollView。

项目上线后发现了新的问题,h5关于滑动的js都无法执行。

原因分析:

引用Coordinator layout 和 WebView中的话是:

如果将webview放在NestedScrollView中,height是wrap_contents,并且webview扩展为页面的大小。 因此无法垂直滚动。 滚动是在NestedScrollView而不是webview本身发生的。
所以页面中没有js的结果会看到任何滚动事件,所以它不知道你已经滚动到页面的末尾加载更多的内容。
硬件层也由GL纹理支持,并且它们具有最大尺寸(这是最小的屏幕尺寸,尽管通常不会大得多)。 如果视图变得大于最大纹理大小,那么它将不能与硬件层一起使用。 这适用于任何视图,而不仅仅是webview。

建议:

不要将webview放在NestedScrollView中。 不要在wrap_contents模式下使用webview。 让webview滚动网页本身。

解决方案:

自定义webview,由它实现NestedScrollingChild。

package com.ingtube.common.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.core.view.MotionEventCompat;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.ViewCompat;

public class NestedScrollWebView extends ScrollWebView implements NestedScrollingChild {
public NestedScrollWebView(@NotNull Context context) {
super(context);
init();
}

public NestedScrollWebView(@NotNull Context context, @NotNull AttributeSet attrs) {  
    super(context, attrs);  
    init();  
}

public NestedScrollWebView(@NotNull Context context, @NotNull AttributeSet attrs, int defStyleAttr) {  
    super(context, attrs, defStyleAttr);  
    init();  
}  
private int mLastMotionY;

private final int\[\] mScrollOffset = new int\[2\];  
private final int\[\] mScrollConsumed = new int\[2\];

private int mNestedYOffset;

private NestedScrollingChildHelper mChildHelper;

private void init() {  
    mChildHelper = new NestedScrollingChildHelper(this);  
    setNestedScrollingEnabled(true);  
}

@Override  
public boolean onTouchEvent(MotionEvent event) {  
    boolean result = false;

    MotionEvent trackedEvent = MotionEvent.obtain(event);

    final int action = MotionEventCompat.getActionMasked(event);

    if (action == MotionEvent.ACTION\_DOWN) {  
        mNestedYOffset = 0;  
    }

    int y = (int) event.getY();

    event.offsetLocation(0, mNestedYOffset);

    switch (action) {  
        case MotionEvent.ACTION\_DOWN:  
            mLastMotionY = y;  
            startNestedScroll(ViewCompat.SCROLL\_AXIS\_VERTICAL);  
            result = super.onTouchEvent(event);  
            break;  
        case MotionEvent.ACTION\_MOVE:  
            int deltaY = mLastMotionY - y;

            if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {  
                deltaY -= mScrollConsumed\[1\];  
                trackedEvent.offsetLocation(0, mScrollOffset\[1\]);  
                mNestedYOffset += mScrollOffset\[1\];  
            }

            int oldY = getScrollY();  
            mLastMotionY = y - mScrollOffset\[1\];  
            int newScrollY = Math.max(0, oldY + deltaY);  
            deltaY -= newScrollY - oldY;  
            if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {  
                mLastMotionY -= mScrollOffset\[1\];  
                trackedEvent.offsetLocation(0, mScrollOffset\[1\]);  
                mNestedYOffset += mScrollOffset\[1\];  
            }  
            if(mScrollConsumed\[1\]==0 && mScrollOffset\[1\]==0) {  
                trackedEvent.recycle();  
                result = super.onTouchEvent(trackedEvent);  
            }  
            break;  
        case MotionEvent.ACTION\_POINTER\_DOWN:  
        case MotionEvent.ACTION\_UP:  
        case MotionEvent.ACTION\_CANCEL:  
            stopNestedScroll();  
            result = super.onTouchEvent(event);  
            break;  
    }  
    return result;  
}

// NestedScrollingChild

@Override  
public void setNestedScrollingEnabled(boolean enabled) {  
    mChildHelper.setNestedScrollingEnabled(enabled);  
}

@Override  
public boolean isNestedScrollingEnabled() {  
    return mChildHelper.isNestedScrollingEnabled();  
}

@Override  
public boolean startNestedScroll(int axes) {  
    return mChildHelper.startNestedScroll(axes);  
}

@Override  
public void stopNestedScroll() {  
    mChildHelper.stopNestedScroll();  
}

@Override  
public boolean hasNestedScrollingParent() {  
    return mChildHelper.hasNestedScrollingParent();  
}

@Override  
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int\[\] offsetInWindow) {  
    return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);  
}

@Override  
public boolean dispatchNestedPreScroll(int dx, int dy, int\[\] consumed, int\[\] offsetInWindow) {  
    return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);  
}

@Override  
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {  
    return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);  
}

@Override  
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {  
    return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);  
}

}

参考链接:

解决coordinatorlayout嵌套webView遇到的问题