【问题标题】:How to disable "expand" from AppBarLayout in fragment that has a NestedScrollView?如何在具有 NestedScrollView 的片段中禁用 AppBarLayout 的“扩展”?
【发布时间】:2026-01-29 00:05:01
【问题描述】:

我有两个问题:

1) 当我的片段中没有 NestedScrollView 时,我能够阻止“扩展”功能,但是当我这样做时,它会继续扩展,即使使用:

appBarLayout.setExpanded(false);
appBarLayout.setActivated(false);

当我在片段中有 NestedScrollView 时,有什么方法可以防止工具栏的扩展?

2) 即使我没有 NestedScrollView,当我在工具栏中触摸手指并向下和向上滚动时,我仍然可以展开它。 “展开和折叠”仍然有效。

当我用手指触摸工具栏并向下和向上滚动时,如何禁用折叠和展开工具栏的操作?

谢谢。

Edit1(更多信息):

这是我的片段的代码,在 FrameLayout 内。

<android.support.v4.widget.NestedScrollView>

    <LinearLayout>

        <TextView />

        <android.support.v7.widget.RecyclerView />

    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

这是我的活动结构:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <android.support.design.widget.CoordinatorLayout>

        <android.support.design.widget.AppBarLayout>

            <android.support.design.widget.CollapsingToolbarLayout>

                <android.support.v7.widget.Toolbar />

            </android.support.design.widget.CollapsingToolbarLayout>

        </android.support.design.widget.AppBarLayout>

        <FrameLayout
            android:id="@+id/frame_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    </android.support.design.widget.CoordinatorLayout>

    ...

</android.support.v4.widget.DrawerLayout>

编辑 2:现在剩下的唯一问题是: 当我在片段中有 NestedScrollView 时,有什么方法可以防止工具栏的扩展?

【问题讨论】:

    标签: android android-layout android-support-library android-coordinatorlayout android-design-library


    【解决方案1】:

    到目前为止,我还没有遇到过这个问题,当我需要它可折叠或可展开时,我通过更改 AppBarLayout height 来解决这个问题。所以,首先,您需要在默认的dimens.xml 文件中定义接下来的两项:

    <dimen name="toolbar_height">56dp</dimen>
    <dimen name="toolbar_expanded_height">256dp</dimen> // this can be whatever you need
    

    然后防止AppBarLayoutToolbar展开/折叠的完整方法是:

    public void disableCollapse() {
        appbar.setActivated(false);
        //you will need to hide also all content inside CollapsingToolbarLayout
        //plus you will need to hide title of it
        backdrop.setVisibility(View.GONE);
        shadow.setVisibility(View.GONE);
        collapsingToolbar.setTitleEnabled(false);
    
        AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams();
        p.setScrollFlags(0);
        collapsingToolbar.setLayoutParams(p);
        collapsingToolbar.setActivated(false);
    
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
        lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_height);
        appbar.requestLayout();
    
        //you also have to setTitle for toolbar
        toolbar.setTitle(title); // or getSupportActionBar().setTitle(title);
    }
    

    您可能还需要将状态栏高度添加到工具栏的高度,如果您使用fitsSystemWindows=true,那么您需要更改

    lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_height);
    

    lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_height) + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? getStatusBarHeight() : 0);
    

    getStatusBarHeight()的方法实现是:

    protected int getStatusBarHeight() {
        int result = 0;
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }
    

    而且,最后,如果你想让你的AppBarLayoutToolbar 再次可折叠/展开,你必须使用下一个方法:

    public void enableCollapse() {
        appbar.setActivated(true);
        collapsingToolbar.setActivated(true);
    
        //you will need to show now all content inside CollapsingToolbarLayout
        //plus you will need to show title of it
        backdrop.setVisibility(View.VISIBLE);
        shadow.setVisibility(View.VISIBLE);
        collapsingToolbar.setTitleEnabled(true);
    
        AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams();
        p.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
        collapsingToolbar.setLayoutParams(p);
    
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
        lp.height = getResources().getDimensionPixelSize(R.dimen.toolbar_expanded_height);
        appbar.requestLayout();
    
        //you also have to setTitle for toolbar
        toolbar.setTitle(title); // or getSupportActionBar().setTitle(title);
    }
    

    希望有帮助!

    【讨论】:

    • 嘿 rom4ek,感谢您的回答。当我应用您的解决方案时,发生了两件事:1)我的头衔不见了。 2)即使我把它放在一个postDelayed中,在工具栏折叠后执行,工具栏上的图像再次显示,但只有我指定的高度。
    • 嘿,我完全忘记了一些事情:1)每次禁用/启用折叠时都需要更新标题+您还必须处理启用/禁用的折叠工具栏标题。 2)您需要根据禁用/启用折叠隐藏/显示CollapsingToolbarLayout内的所有内容。请检查我编辑的方法以启用/禁用折叠。
    • 嘿,rom4ek,我们快到了。当我使用 disableCollapse 方法时,现在发生的行为是:工具栏不可见,然后再次可见,导致用户体验不佳。您可以模拟我所说的将内容滚动到底部,然后替换片段。显然,工具栏保持在 0 高度,然后才成为我指定的高度。
    • 好的,我可以用 postDelayed 处理这个问题。我会接受你的回答,但我真的希望他们能用一些优雅的方法来处理这些情况,呵呵
    • 嗯,我没有遇到过这个问题,尽管我也将它与片段一起使用。很高兴您解决了它,并感谢您的赏金:)
    【解决方案2】:

    要阻止用手指在AppBarLayout 上滚动,您必须使用DragCallback 界面:

    AppBarLayout layout = ...;
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) layout.getLayoutParams();
    AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
    behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
        @Override
        public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
            return false;
        }
    });
    

    要防止AppBarLayoutNestedScrollView 滚动而滚动,您必须从NestedScrollView 中删除该行为:

    NestedScrollView nestedScrollView = ...;
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) nestedScrollView.getLayoutParams();
    params.setBehavior(null);
    

    您可以尝试的另一件事是从 AppBarLayout 子项中删除滚动标志:

    AppBarLayout layout = ...;
    View child = layout.getChildAt(0);
    AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) child.getLayoutParams();
    params.setScrollFlags(0);
    

    【讨论】:

    • 您好,natario,感谢您的回答。第一部分对我有用!我可以控制触摸何时起作用。现在,第二部分。问题是,我的 NestedScrollView 并不直接位于 CoordinatorLayout 内部。我必须在 CoordinatorLayout 内使用 FrameLayout 来管理片段替换。而且FrameLayout没有setBehavior这样的方法。有什么解决办法吗?谢谢!
    • 将我的示例中的 NestedScrollView 替换为 Coordinator 的直接子级。在您的布局中必须有一个具有 scrolling_view_behavior 的直接 Coordinator 子级。您必须使用我发布的代码删除该行为。
    • 没有工作.. 我用更多信息编辑了我的问题。在出现这个问题之前,我已经在 FrameLayout 中设置了一个行为,可以按照我的意愿工作,也许我做错了?我应该使用不同的吗?
    • 更多信息,当我从 FrameLayout 中删除该行为时,当我向下滚动时,折叠工具栏现在位于我的框架布局上方。
    • 你是对的,我的回答是错误的。试试ViewCompat.setNestedScrollingEnabled(frameLayout, false)(在框架布局上),或者,如果这不起作用,nestedScrollView.setNestedScrollingEnabled(false)(在 NSV 上)。保持行为不变。
    【解决方案3】:

    在您的特定片段 onViewCreated 方法中添加

     private void disableCollapsing() {
        AppBarLayout layout = ((HomeActivity) getActivity()).appBarLayout;
        View child = layout.getChildAt(0);
        AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) child.getLayoutParams();
        params.setScrollFlags(0);
    }
    

    和reActive在销毁时崩溃

    private void enableCollapsing() {
        AppBarLayout layout = ((HomeActivity) getActivity()).appBarLayout;
        View child = layout.getChildAt(0);
        AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) child.getLayoutParams();
        params.setScrollFlags(1);
    }
    

    【讨论】: