material-components / material-components-android

Modular and customizable Material Design UI components for Android
Apache License 2.0
16.37k stars 3.07k forks source link

[CollapsingToolbarLayout] Force NOT apply system window inset top #2391

Open Back4fire opened 3 years ago

Back4fire commented 3 years ago

Don't apply the system window inset top even if the height is wrap_content. Consider the background image of the collapsingtooblarlayout is a fixed ratio of width and height. If the layout is as follows, the real height of the collapsingtooblarlayout is the sum of the image height and the inset top.

<com.google.android.material.appbar.CollapsingToolbarLayout android:id="@+id/toolbar_layout" style="@style/Widget.MaterialComponents.Toolbar.Primary" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed" app:toolbarId="@+id/toolbar">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fitsSystemWindows="true">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:background="#FF0000"
                android:scaleType="centerCrop"
                app:layout_constraintDimensionRatio="4:3"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/Theme.MyApplication.PopupOverlay"
            app:title="Toolbar" />
    </com.google.android.material.appbar.CollapsingToolbarLayout>

It seems the height of the collpasingtoolbarlayout must be set to a specific value in the run time in order to achieve this. If there is an attr such as forceNotApplySystemWindowInsetTop, it can be done in the layout XML file.

drchen commented 3 years ago

Hi can you provide some screenshots about what's your current issue and what's your expected result?

It's hard to tell the exact reason why you need forceNotApplySystemWindowInsetTop in your layout XML.

As a possible solution you can also call setOnApplyWindowInsetsListener and consume the window insets when it's called, so the window insets won't be automatically applied.

Back4fire commented 3 years ago

e.g. there is a product detail activity as follows:

https://user-images.githubusercontent.com/20295792/136561781-893ee854-0fb6-4cf4-9060-34d5d26e669e.mp4

The header consists of a fixed-aspect-ratio image and a toolbar. The layout is as follows:

device-2021-10-08-150605

There is a natural thought that put an ImageView inside a ConstraintLayout with the attr app:layout_constraintDimensionRatio to keep the aspect ratio. Then wrap the ConstraintLayout and the Toolbar with a CollapsingToolbarLayout. The following is the skeleton of the code:

<com.google.android.material.appbar.CollapsingToolbarLayout ... android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true">

        <ImageView
            ...
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintDimensionRatio="4:3" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.appcompat.widget.Toolbar
        ...
         />
</com.google.android.material.appbar.CollapsingToolbarLayout>

But the real height of the CollapsingToolbarLayout will be the height of the ImageView plus the top inset because the height of it is wrap_content.

The solution mentioned above cannot work in this layout. If the window insets are consumed, the CollapsingToolbarLayout will not be able to offset the Toolbar correctly.

For now my solution is to calculate the height of the ImageView by the screen width and the aspect ratio in runtime. The set the height of the CollapsingToolbarLayout to this value. If there is an attr forceNotApplySystemWindowInsetTop, it will be more convenient.