22

I've created an AppBar layout like this

<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>

it works and casts a shadow in the 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>

However when I put it into the CoordinatorLayout shadow is gone:

<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>

How can I make appbar to show its shadow again?

enter image description here

Kata Lune
  • 411
  • 1
  • 4
  • 11

4 Answers4

17

This is actually an implementation detail of CollapsingToolbarLayout, as seen in the source code:

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);
}

Which removes the elevation when the CollapsingToolbarLayout is showing non-pinned elements - by default, it'll only have elevation when only pinned children are visible.

ianhanniballake
  • 155,909
  • 19
  • 351
  • 362
  • I wonder why this answer got many upvotes. What if the author has no pinned elements? – Leo Droidcoder Dec 07 '19 at 17:52
  • @LeoDroidcoder - the vast majority of `CollapsingToolbarLayout` usages have a pinned `Toolbar` within it, hence the name. You probably don't want or need to use `CollapsingToolbarLayout` at all if that isn't the case. – ianhanniballake Dec 07 '19 at 18:52
  • 1
    There might be a pinned `Toolbar` which will let to draw a shadow in the collapsed state of `CollapsingToolbarLayout`. But what many developers want is to draw the shadow in an expanded state as well, i.e. with any value of `verticalOffset`. Even though it might contradict with the Material Design guidelines – Leo Droidcoder Dec 10 '19 at 21:26
9

the reason is above,try this to solve:

appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            //some other code here
            ViewCompat.setElevation(appBarLayout, The Elevation In Px);
        }
    });
halfCup
  • 91
  • 1
  • 3
  • Works inconsistently on Android 10 with the latest AndroidX lib : sometimes the elevation is the one you asked for, sometimes it's the default one (when scrolling in the NestedView) and sometimes it's simply gone (when the CollapsingToolbarLayout is in expanded state). – flawyte Mar 16 '20 at 12:31
3

The solution is to use app:elevation=0dp to remove the default elevation and set android:translationZ to the elevation you want.

Note : The code below uses the latest AndroidX / Material libraries and might not work if you're using the old support library

<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
    -->

The documentation for AppBarLayout # setTargetElevation() states that you can set a custom elevation value using the app:elevation attribute, but it didn't work for me for values greater than 0dp, so I'm using translationZ as a workaround.

flawyte
  • 7,678
  • 4
  • 44
  • 63
1

setTargetElevation() is now deprecated for AppBarLayout.

The new correct implementation for applying custom elevation to an AppBarLayout based on the state of the layout is to use a StateListAnimator. material-components uses this as you can see here

I've added an example implementation of always showing AppBarLayout elevation here in this gist.

All you need is to 1. create a custom state list animator under /res/animator and 2. set the AppBarLayout's StateListAnimator like so:

appBarLayout.stateListAnimator = AnimatorInflater.loadStateListAnimator(context, R.animator.appbar_always_elevated_state_list_animator)
w3bshark
  • 2,519
  • 1
  • 24
  • 35