Search code examples
javaandroidandroid-design-libraryandroiddesignsupportandroid-collapsingtoolbarlayout

CollapsingToolbarLayout elevation not working and anchored FloatingActionButton not returning


I've been trying to implement a layout similar to this from the material design guidelines, using the new Android Design Support Library. The CollapsingToolbarLayout seems to be the way to go, but it ignores any attempt to add elevation. Furthermore, if I set the height of the AppBarLayout to anything under about 144dp, the FloatingActionButton will pop out, but not return. Here's my xml:

<android.support.design.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"
android:fitsSystemWindows="true">

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="144dp"
    android:fitsSystemWindows="true"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:expandedTitleMarginEnd="72dp"
        app:expandedTitleMarginStart="72dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:paddingLeft="72dp"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

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

<android.support.v7.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/fab_margin"
    android:src="@drawable/ic_person_add_white_24dp"
    app:borderWidth="0dp"
    app:fabSize="mini"
    app:layout_anchor="@id/appbar"
    app:layout_anchorGravity="bottom|left|start"/>


Solution

  • After diving into the source code, I discovered the FloatingActionButton, when attached to the AppBarLayout, is set to appear only when the space available is <=appBarLayout.getMinimumHeightForVisibleOverlappingContent(), which is 2*minimum height(the Toolbar, in this case), plus the status bar. So in portrait on a phone, 56*2+26 = 138dp. I confirmed this by setting mine to 138dp, which works, and 137dp does not. If you want to get around this, you can either override getMinimumHeightForVisibleOverlappingContent() in AppBarLayout, or the following method in FloatingActionButton:

    public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
            if(dependency instanceof SnackbarLayout) {
                this.updateFabTranslationForSnackbar(parent, child, dependency);
            } else if(dependency instanceof AppBarLayout) {
                AppBarLayout appBarLayout = (AppBarLayout)dependency;
                if(this.mTmpRect == null) {
                    this.mTmpRect = new Rect();
                }
    
                Rect rect = this.mTmpRect;
                ViewGroupUtils.getDescendantRect(parent, dependency, rect);
                if(rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
                    if(!this.mIsAnimatingOut && child.getVisibility() == 0) {
                        this.animateOut(child);
                    }
                } else if(child.getVisibility() != 0) {
                    this.animateIn(child);
                }
            }
            return false;
        }
    

    As for the CollapsingToolbarLayout elevation, I haven't found a workaround yet.