隐藏AppBarLayout并将其空间让给其余视图。

24
我有一个使用新设计库的相当标准的布局:

<AppBarLayout>
    <CollapsingToolbarLayout>
        <ImageView/>
        <Toolbar/>
    </CollapsingToolbarLayout>
</AppBarLayout>

<android.support.v4.widget.NestedScrollView/> <!-- content here -->

我想要做的是通过编程完全隐藏整个AppBarLayout,暂时摆脱Toolbar及其折叠特性。

所以我调用了这个方法:

private void disableCollapsing() {
    AppBarLayout.LayoutParams p = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
    p.setScrollFlags(0);
    collapsingToolbarLayout.setLayoutParams(p);
}

要禁用折叠行为(很有效),最后使用以下代码:

@Override
public void hide() {
    final AppBarLayout layout = (AppBarLayout) findViewById(R.id.appbar);

    layout.animate().translationY(-layout.getHeight())
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    layout.setVisibility(View.GONE);
                }
            }).start();
}

我让AppBarLayout向上平移(效果流畅),并在动画集结束时将其可见性设置为View.GONE

问题

在动画结束时,无论我是否将可见性设置为GONE,我都无法获得之前由AppBarLayout占用的空间。我的NestedScrollView仍然局限于屏幕的下半部分,就好像AppBarLayout仍然存在一样(但实际上不是这样)。我该如何解决?

隐藏之前:

Before

隐藏之后(AppBar向上平移):

After

可以看到,顶部空间为空且无法触及。滚动视图在之前的边距内滚动,就好像CoordinatorLayout没有测量到可见性的变化。

  • 我已尝试调用coordinator.requestLayout(),但没有成功。

  • 我还尝试将AppBarLayout设置为我的NestedScrollView的app:anchor,但那会弄乱一切——甚至在隐藏之前,滚动视图就会占据整个屏幕。

  • 我考虑创建一个自定义Behavior,在进入这种隐藏AppBar模式时将其设置为滚动视图,但我无从开始。


你找到这个问题的解决方案了吗?我也遇到了同样的问题。在Chris Bane的Cheesesquare应用程序中,在奶酪详情屏幕中删除两个TextView,问题也会重现。 - Aftab Ali
@AftabAli,请查看这个问题,看看是否有帮助。 - natario
请查看我在 https://stackoverflow.com/questions/37364425/how-to-hide-show-widget-appbarlayout-on-click-in-android-app/73741324#73741324 上的答案。 - Parikshit.S.Shekhawat
5个回答

27

是的,这看起来像一个bug,我解决了这个问题,将我的应用程序的appbar高度设置为0:

android.support.design.widget.AppBarLayout appbar = (android.support.design.widget.AppBarLayout) findViewById(R.id.appbar);

CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();

lp.height = 0;

appbar.setLayoutParams(lp);

1
我曾将可见性设置为gone,同时高度也为0。但只使用高度为0才是正确的解决方案。 - JCarlosR
1
很棒的解决方案。我很好奇如何通过获取lp来调整高度,在我的情况下(隐藏它)将值设置为0。我发现有用的一种情况是(显示它),只需简单地执行 lp.height = CoordinatorLayout.LayoutParams.WRAP_CONTENT; 或者您的布局所需的任何高度(假设协调布局)。 - EvOlaNdLuPiZ

4

如上所述,设置Coordinator.LayoutParams#height可解决此问题。

然而,我想表达的是何时/如何出现这种情况(不一定是为什么):

CollaspingToolbarLayout只有在其app:layout_scrollFlags属性设置为exitUntilCollapsed,并且其嵌套的ToolBar也定义了app:layout_collapseMode="pin"后,才会出现此行为。通过这些标志的组合,Toolbar将固定在屏幕顶部,这是有意的,有时也是可取的。

(为简洁起见剪辑)

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    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">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <!-- some other component here, i.e ImageView -->

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:gravity="top"
                app:layout_collapseMode="pin" />

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <!-- some scrolling view/layout -->

</androidx.coordinatorlayout.widget.CoordinatorLayout>

在 Kotlin + ViewBinding 中,在 Fragment/Activity 创建视图后:
binding.appbar.updateLayoutParams<CoordinatorLayout.LayoutParams> {
    height = 0
}

对我来说,我需要捕获 AppBarLayout 的高度,然后将其隐藏,以便在需要显示时将其恢复到原始高度。

private var appbarLayoutHeight = 0
private fun hideAppBar() {
    appbarLayoutHeight = binding.appbar.measuredHeight
    binding.appbar.updateLayoutParams<CoordinatorLayout.LayoutParams> {
        height = 0
    }
}
private fun showAppBar() {
    binding.appbar.updateLayoutParams<CoordinatorLayout.LayoutParams> {
        height = appbarLayoutHeight
    }
}

声明:使用 ViewBinding 和 Kotlin 并不是实现这个的必要条件,这只是我用来获取 AppBarLayoout 并使代码更加简洁易懂的方式。


0

感谢 @Caleb Kleveter,这是我的 Kotlin 代码

    val appBarLayout = activity?.findViewById<AppBarLayout>(R.id.app_bar_layout)
    val lp = appBarLayout?.layoutParams
    lp?.height = 0;
    appBarLayout?.layoutParams = lp

0

这对我有效。只需切换应用程序栏的开/关状态。

private boolean hide = true;
public void toggleAppBar() {

    // Calculate ActionBar height
    TypedValue tv = new TypedValue();
    int actionBarHeight = 0;
    if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
        actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
    }


    CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appBarLayout.getLayoutParams();
    lp.height = hide ? 0 : actionBarHeight;
    appBarLayout.setLayoutParams(lp);
    appBarLayout.setExpanded(!hide, true);

    hide = !hide;

appbar_layout.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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBarLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_main" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

-2

以下方法同样有效

appBarLayout.setExpanded(false, false);
appBarLayout.setVisibility(View.GONE);

这个什么时候可用?在com.android.support:design:22.2.1中似乎不起作用。 - atreat
2
这段代码不起作用。当向下滚动时,它会再次显示空的AppBarLayout。 - HungNM2
这个不起作用。你在发布之前试过实践吗? - Serg Burlaka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接