Coordinator Layout Behavior失效:WebView滚动Toolbar显隐功能未实现
解决WebView配合CoordinatorLayout滚动隐藏Toolbar失效的问题
看起来你已经搭好了基础结构,但WebView的滚动事件默认不会被AppBarLayout.ScrollingViewBehavior正确识别,再加上SwipeRefreshLayout的包裹,容易出现事件拦截的情况,咱们一步步来修复:
第一步:确认XML结构的正确性
先把你的XML结构补全并修正关键点:
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" /> </com.google.android.material.appbar.AppBarLayout> <androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
这里要确保:
AppBarLayout直接作为CoordinatorLayout的子视图SwipeRefreshLayout正确设置了app:layout_behavior="@string/appbar_scrolling_view_behavior"Toolbar的scrollFlags确实是scroll|enterAlways
第二步:让WebView的滚动事件被CoordinatorLayout感知
WebView的滚动是内部实现的,默认不会把滚动事件传递给外层的ScrollingViewBehavior,所以我们需要手动把滚动事件传递给AppBarLayout的Behavior:
方案一:API 23+ 直接用原生WebView监听
如果你的最低适配版本是API 23及以上,直接给WebView设置滚动监听即可:
WebView webView = findViewById(R.id.webview); AppBarLayout appBarLayout = findViewById(R.id.appbar); CoordinatorLayout coordinator = findViewById(R.id.coordinator); webView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> { CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams(); AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior(); if (behavior != null) { // 计算滚动差值,传递给Behavior处理 int dy = scrollY - oldScrollY; behavior.onNestedPreScroll(coordinator, appBarLayout, v, 0, dy, new int[2], 0); } });
方案二:兼容低版本的自定义WebView
如果需要适配API 23以下的版本,自定义一个能暴露滚动事件的WebView:
public class ObservableWebView extends WebView { private OnScrollChangeListener mScrollListener; public ObservableWebView(Context context) { super(context); } public ObservableWebView(Context context, AttributeSet attrs) { super(context, attrs); } public ObservableWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mScrollListener != null) { mScrollListener.onScrollChange(this, l, t, oldl, oldt); } } public void setOnScrollChangeListener(OnScrollChangeListener listener) { mScrollListener = listener; } public interface OnScrollChangeListener { void onScrollChange(WebView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); } }
然后替换XML里的WebView,再设置监听:
ObservableWebView webView = findViewById(R.id.webview); // 后续监听代码和方案一一致,把WebView换成ObservableWebView即可
第三步:处理SwipeRefreshLayout的事件冲突
有时候SwipeRefreshLayout会拦截顶部的滚动事件,导致WebView的滚动监听没触发,这时候可以设置一个回调,只有当WebView滚动到顶部时才允许下拉刷新:
SwipeRefreshLayout swipeRefresh = findViewById(R.id.swipe_refresh); swipeRefresh.setOnChildScrollUpCallback((parent, child) -> { // 当WebView没有滚动到顶部时,拦截SwipeRefreshLayout的下拉事件 return webView.getScrollY() > 0; });
这样调整之后,WebView向上滚动时Toolbar就会隐藏,向下滚动时会重新显示啦。
内容的提问来源于stack exchange,提问作者user8965395
相关产品推荐
相关产品推荐

