How to set the elevation of an AppBarLayout programmatically in the Android Support Library v24.0.0?

Edit

The AppBarLayout from v24.0.0 uses a StateListAnimator that defines the elevation depending on its state. So using setElevation will have no effect if a StateListAnimator is being used (which happens by default). Set the elevation via the XML or programmatically (both for API >= 21):

StateListAnimator stateListAnimator = new StateListAnimator();
stateListAnimator.addState(new int[0], ObjectAnimator.ofFloat(view, "elevation", 0));
appBarLayout.setStateListAnimator(stateListAnimator);

Old answer

This seems to be an issue of the design support library. The problem is related to the way the elevation is set programmatically, using setElevation. Setting it from the XML is placing a StateListAnimator in the view and not calling setElevation. However, setElevation should work.

Here there is a workaround:

setDefaultAppBarLayoutStateListAnimator(appBarLayout, 0);

@SuppressLint("PrivateResource")
private static void setDefaultAppBarLayoutStateListAnimator(final View view, final float targetElevation) {
    final StateListAnimator sla = new StateListAnimator();

    // Enabled, collapsible and collapsed == elevated
    sla.addState(new int[]{android.R.attr.enabled, android.support.design.R.attr.state_collapsible,
            android.support.design.R.attr.state_collapsed},
            ObjectAnimator.ofFloat(view, "elevation", targetElevation));

    // Enabled and collapsible, but not collapsed != elevated
    sla.addState(new int[]{android.R.attr.enabled, android.support.design.R.attr.state_collapsible,
            -android.support.design.R.attr.state_collapsed},
            ObjectAnimator.ofFloat(view, "elevation", 0f));

    // Enabled but not collapsible == elevated
    sla.addState(new int[]{android.R.attr.enabled, -android.support.design.R.attr.state_collapsible},
            ObjectAnimator.ofFloat(view, "elevation", targetElevation));

    // Default, none elevated state
    sla.addState(new int[0], ObjectAnimator.ofFloat(view, "elevation", 0));

    view.setStateListAnimator(sla);
}

This is taken from what the constructor does, calling a method in the class ViewUtilsLollipop in v24.0.0.


One more possible solution for this is to add android:stateListAnimator="@null" to your AppBarLayout as shown below.

<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:stateListAnimator="@null"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">