You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android布局:滑动FragmentContainerView时隐藏Toolbar的实现方案

实现滑动隐藏Toolbar的解决方案(适配FragmentContainerView场景)

方案一:让Fragment内的可滑动视图主动分发滚动事件

CoordinatorLayout的AppBarLayout滚动逻辑依赖子视图传递的滚动事件,FragmentContainerView本身不会触发滚动事件,因此需要让其内部的可滑动视图主动将事件传递给CoordinatorLayout:

  • WebView场景:
    自定义WebView实现NestedScrollingChild接口,通过NestedScrollingChildHelper分发滚动事件:

    public class NestedScrollWebView extends WebView implements NestedScrollingChild {
        private final NestedScrollingChildHelper mChildHelper;
        private int mLastY;
    
        public NestedScrollWebView(Context context) {
            this(context, null);
        }
    
        public NestedScrollWebView(Context context, AttributeSet attrs) {
            this(context, attrs, android.R.attr.webViewStyle);
        }
    
        public NestedScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mChildHelper = new NestedScrollingChildHelper(this);
            setNestedScrollingEnabled(true);
        }
    
        @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
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
            int dy = t - mLastY;
            startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
            dispatchNestedPreScroll(0, dy, null, null);
            mLastY = t;
        }
    }
    

    在Fragment布局中使用该自定义WebView,即可让CoordinatorLayout接收到滚动事件,驱动Toolbar隐藏/显示。

  • RecyclerView/ListView场景:
    这类视图默认已实现NestedScrollingChild接口,只需确保布局中android:nestedScrollingEnabled="true"(默认开启),滚动事件会自动传递给CoordinatorLayout。

方案二:给FragmentContainerView自定义Behavior

如果不想修改Fragment内部视图,可给FragmentContainerView编写自定义Behavior,监听其内部子视图的滚动事件并主动通知AppBarLayout:

public class FragmentContainerScrollBehavior extends AppBarLayout.ScrollingViewBehavior {
    private View mChildView;

    public FragmentContainerScrollBehavior() {
    }

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

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
        boolean result = super.onLayoutChild(parent, child, layoutDirection);
        if (child instanceof FragmentContainerView) {
            mChildView = ((FragmentContainerView) child).getChildAt(0);
            if (mChildView != null) {
                setupScrollListener();
            }
        }
        // 监听Fragment切换,更新子视图引用
        parent.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
            if (child instanceof FragmentContainerView) {
                mChildView = ((FragmentContainerView) child).getChildAt(0);
                if (mChildView != null) {
                    setupScrollListener();
                }
            }
        });
        return result;
    }

    private void setupScrollListener() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mChildView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
                int dy = scrollY - oldScrollY;
                dispatchNestedScrollEvent(v, dy);
            });
        } else {
            if (mChildView instanceof WebView) {
                ((WebView) mChildView).setOnScrollChangeListener((View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) -> {
                    int dy = scrollY - oldScrollY;
                    dispatchNestedScrollEvent(v, dy);
                });
            } else if (mChildView instanceof RecyclerView) {
                ((RecyclerView) mChildView).addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
                        dispatchNestedScrollEvent(recyclerView, dy);
                    }
                });
            }
        }
    }

    private void dispatchNestedScrollEvent(View v, int dy) {
        if (v instanceof NestedScrollingChild) {
            ((NestedScrollingChild) v).startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
            ((NestedScrollingChild) v).dispatchNestedPreScroll(0, dy, null, null);
        }
    }
}

在布局中给FragmentContainerView设置该Behavior:

app:layout_behavior="com.abc.myApp.features.main.FragmentContainerScrollBehavior"

方案三:修复NestedScrollView嵌套FragmentContainerView的显示问题

之前嵌套后视图不显示,核心原因是NestedScrollView未开启fillViewport属性,导致内容高度被压缩为0,按以下步骤修复:

  1. 修改布局,将FragmentContainerView嵌套进NestedScrollView:
<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

</androidx.core.widget.NestedScrollView>
  1. 确保Fragment的根布局高度设置为match_parent或wrap_content,避免内容被截断。
  2. 对于WebView场景,需开启自适应设置:
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);

注意:此方案可能导致内部可滚动视图与NestedScrollView出现双重滚动冲突,需根据实际场景禁用内部视图的滚动(如WebView设置setNestedScrollingEnabled(false))。

内容的提问来源于stack exchange,提问作者Franklin84

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 15:55:11