androidkotlinandroid-toolbarandroid-collapsingtoolbarlayoutinsets

Change insets for collapsing toolbar depending on its state


I have collapsing toolbar and some layout in it I want to collapse. To prevent view going under status bar, I use system insets to set margin for collapsing toolbar. I extracted AppBarLayout to separate file and included it inside CoordinatorLayout:

<com.google.android.material.appbar.AppBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/action_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

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

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?actionBarSize"
            android:background="@color/colorToolbar"
            android:elevation="4dp"
            android:focusable="true"
            android:focusableInTouchMode="true"
            app:contentInsetStartWithNavigation="0dp"
            app:layout_collapseMode="pin">

            ...
        </androidx.appcompat.widget.Toolbar>

        <com.google.android.material.card.MaterialCardView
            android:id="@+id/bonuses_widget"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:cardCornerRadius="14dp"
            app:cardElevation="3dp"
            app:layout_collapseMode="parallax">

            ...
        </com.google.android.material.card.MaterialCardView>
    </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>

Margins for MaterialCardView are set from code because layout doesn't support addition. I add margins for collapsing toolbar using insets:

ViewCompat.setOnApplyWindowInsetsListener(action_bar) { _, insets ->
    collapsing_toolbar.setMarginTop(insets.systemWindowInsetTop)
    insets
}

This works well when collapsing toolbar is expanded, but in collapsed state toolbar goes under status bar:

I have read this question, have implemented AppBarStateChangeListener and use it like this:

action_bar.addOnOffsetChangedListener(object : AppBarStateChangeListener() {
    override fun onStateChanged(appBarLayout: AppBarLayout, state: State) {
        if (state == State.COLLAPSED) {
            ViewCompat.setOnApplyWindowInsetsListener(collapsing_toolbar) { _, insets ->
                toolbar.setMarginTop(insets.systemWindowInsetTop)
                insets
            }
        }
        if (state == State.EXPANDED) {
            ViewCompat.setOnApplyWindowInsetsListener(collapsing_toolbar) { _, insets ->
                toolbar.setMarginTop(0)
                insets
            }
        }
    }
})

This didn't help, as I can understand so far, status bar's insets is already handled by action bar and collapsing toolbar has nothing to handle.
I also tried to margin to toolbar at the same time with collapsing toolbar, it worked but leaded to another problem:

After all I tried to remove insets and just set android:fitsSystemWindows="true" to action bar, this fixes problem with toolbar under status bar, but status bar unexpectedly gets strange color (purple) which isn't represented in app colors.
Hope someone knows hot to handle with insets properly in this case.


Solution

  • Eventually I found suitable solution:

    ViewCompat.setOnApplyWindowInsetsListener(action_bar) { view, insets ->
        view.updatePadding(top = insets.systemWindowInsetTop)
        insets
    }
    

    There is still problem with white background under status bar (I need it to be dark as on left screenshots), but initial problem is solved.