CoordinatorLayout和AppBarLayout的高度差问题

22

我已经创建了一个类似这样的AppBar布局

<android.support.design.widget.AppBarLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/appbar_layout"
    android:layout_height="@dimen/app_bar_height"
    android:layout_width="match_parent"
    android:fitsSystemWindows="true"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:elevation="20dp">

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

它有效地在LinearLayout中发挥作用并投下阴影:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/app_bar_large" />
</LinearLayout>

然而,当我把它放到CoordinatorLayout中,阴影就消失了:

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/app_bar_large" />
</android.support.design.widget.CoordinatorLayout>

我该如何使应用栏重新显示其阴影?

在此输入图片描述

4个回答

18

这实际上是CollapsingToolbarLayout的一项实现细节,可以在源代码中看到:

if (Math.abs(verticalOffset) == scrollRange) {
  // If we have some pinned children, and we're offset to only show those views,
  // we want to be elevate
  ViewCompat.setElevation(layout, layout.getTargetElevation());
} else {
  // Otherwise, we're inline with the content
  ViewCompat.setElevation(layout, 0f);
}

默认情况下,CollapsingToolbarLayout 仅在显示固定元素时具有阴影效果。使用本代码可在非固定元素显示时也去除阴影。


我想知道为什么这个答案得到了很多赞。如果作者没有固定元素会怎样呢? - Leo DroidCoder
@LeoDroidcoder - 绝大多数CollapsingToolbarLayout的用法都包含了一个固定的Toolbar,因此得名。如果不是这种情况,您可能根本不需要使用CollapsingToolbarLayout - ianhanniballake
1
可能会有一个固定的“工具栏”,它将允许在“CollapsingToolbarLayout”折叠状态下绘制阴影。但是,许多开发人员希望在展开状态下也绘制阴影,即使在任何“verticalOffset”的值下都是如此。尽管这可能与Material Design指南相矛盾。 - Leo DroidCoder

9

问题的原因在上面,尝试以下步骤来解决:

appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            //some other code here
            ViewCompat.setElevation(appBarLayout, The Elevation In Px);
        }
    });

在最新的AndroidX库上,它在Android 10上表现不一致:有时高度是您要求的那个,有时是默认的(当在嵌套视图中滚动时),有时则完全消失(当CollapsingToolbarLayout处于展开状态时)。 - Mickäel A.

5
解决方法是使用app:elevation=0dp来去除默认的高度,并将android:translationZ设置为所需的高度。

注意:以下代码使用最新的AndroidX / Material库,如果您使用旧的支持库可能无法正常工作。

<com.google.android.material.appbar.AppBarLayout
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:translationZ="8dp"
    app:elevation="0dp">

    <!--
      * `app:elevation=0dp` disables the default shadow that is automatically added on
      scroll ; other values e.g. `6dp` are ignored despite what the official doc says
      (see below)
      * so instead we're using `android:translationZ` to add a shadow with a custom
      elevation
    -->
AppBarLayout # setTargetElevation() 的文档指出,你可以使用app:elevation属性设置自定义的高度值,但对于大于0dp的值,这种方法对我不起作用,因此我使用translationZ作为解决方法。

是的,高度值太疯狂了。应该把它删除并使用translationZ替代。谢谢。 - Tony

1

setTargetElevation()已经不再适用于AppBarLayout。

根据布局状态应用自定义高度到AppBarLayout的新正确实现是使用StateListAnimator。正如您可以在这里看到的那样,material-components使用了它。

我已经在这个代码片段中添加了一个始终显示AppBarLayout高度的示例实现。

你所需要做的就是:1. 在/res/animator下创建一个自定义状态列表动画器;2. 设置AppBarLayout的StateListAnimator,如下所示:

appBarLayout.stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.appbar_always_elevated_state_list_animator)

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