Как применить вставки к CollapsingToolbarLayout с изображением внутри, чтобы изображение на панели инструментов отображалось за строкой состояния?

Я пытаюсь настроить полноэкранную активность для Android 10 с помощью вставок. Я хотел, чтобы изображение на панели инструментов отображалось за строкой состояния. Я пытался использоватьandroid:fitsSystemWindows флаг в разных комбинациях, но не работает, AppBarLayoutне имеет правильного заполнения, а строка состояния слегка перекрывает элементы управления меню панели инструментов. Итак, я использовал удобныйWindowInsetsCompatwrapper, библиотека Insetter от Chris Banes, для установки отступов в соответствии с вставками системного окна.

Вот мой макет:

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"

  android:id="@+id/book_activity_root"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:animateLayoutChanges="true"
  tools:context="com.bookcrossing.mobile.ui.bookpreview.BookActivity"
  >

  <androidx.core.widget.NestedScrollView
    android:id="@+id/nestedScrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    >
    ...
  </androidx.core.widget.NestedScrollView>
  <com.google.android.material.appbar.AppBarLayout
    android:id="@+id/toolbarContainer"
    android:layout_width="match_parent"
    android:layout_height="220dp"
    >
    <com.google.android.material.appbar.CollapsingToolbarLayout
      android:id="@+id/collapsingToolbarContainer"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:contentScrim="?attr/colorPrimary"
      app:expandedTitleGravity="bottom"
      app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
      app:titleEnabled="true"
      app:toolbarId="@id/toolbar"
      >

      <ImageView
        android:id="@+id/cover"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:contentDescription="@string/cover_description"
        android:scaleType="centerCrop"
        android:cropToPadding="true"
        app:layout_collapseMode="parallax"
        app:layout_collapseParallaxMultiplier="0.5"
        />

      <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:layout_collapseMode="pin"
        app:layout_scrollFlags="scroll|enterAlways"
        tools:title="War and Peace"
        />

    </com.google.android.material.appbar.CollapsingToolbarLayout>
  </com.google.android.material.appbar.AppBarLayout>
  <com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/favorite"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/default_padding"
    android:clickable="true"
    android:focusable="true"
    android:src="@drawable/ic_turned_in_not_white_24dp"
    app:layout_anchor="@id/toolbar_container"
    app:layout_anchorGravity="bottom|right|end"
    />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Вот как я устанавливаю отступы в коде:

    Insetter.setOnApplyInsetsListener(toolbarContainer, (view, windowInsets, initial) -> {
      view.setPadding(initial.getPaddings().getLeft(),
        windowInsets.getSystemWindowInsetTop() + initial.getPaddings().getTop(),
        initial.getPaddings().getRight(), initial.getPaddings().getBottom());
    });

    Insetter.setOnApplyInsetsListener(cover, (view, windowInsets, initial) -> {
      ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
      params.topMargin = windowInsets.getSystemWindowInsetTop() + initial.getMargins().getTop();
      view.setLayoutParams(params);
    });

    Insetter.setOnApplyInsetsListener(nestedScrollView, (view, windowInsets, initial) -> {
      view.setPadding(initial.getPaddings().getLeft(), initial.getPaddings().getTop(),
        initial.getPaddings().getRight(),
        windowInsets.getSystemWindowInsetBottom() + initial.getPaddings().getBottom());
    });

    Insetter.setOnApplyInsetsListener(favorite, (view, windowInsets, initialPadding) -> {
      view.setPadding(initialPadding.getPaddings().getLeft(), initialPadding.getPaddings().getTop(),
        windowInsets.getSystemWindowInsetRight() + initialPadding.getPaddings().getRight(),
        initialPadding.getPaddings().getBottom());
    });

Я установил оконные флаги для полноэкранного режима:

root.setSystemUiVisibility(
      View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

И вот результат:

Строка состояния настроена на прозрачность, синий цвет - это панель инструментов с верхним отступом.

В конечном итоге я бы хотел, чтобы изображение отображалось за строкой состояния, возможно ли это вообще?

Тестирую на эмуляторе Android 10.

3 ответа

Ваши флаги кажутся неправильными. Вы устанавливаете флаг для панели навигации, в то время как вы должны устанавливать флаг для строки состояния.

Вот код, который я использую (Котлин):

requireActivity().window?.decorView?.systemUiVisibility = (
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)

чтобы пользовательский интерфейс отображался за строкой состояния без скрытия строки состояния. Затем я использую эту функцию расширения, которую использую для представлений, которые не должны перекрываться со строкой состояния, например с кнопками и другими элементами управления:

fun View.alignBelowStatusBar() {
this.setOnApplyWindowInsetsListener { view, insets ->
    val params = view.layoutParams as ViewGroup.MarginLayoutParams
    params.topMargin = insets.systemWindowInsetTop
    view.layoutParams = params
    insets
}

}

Таким образом, первые флаги гарантируют, что ваши фоны / изображения будут находиться под строкой состояния. Второй - убедиться, что элементы управления не перекрываются строкой состояния.

Насколько я помню, вам не нужно поддерживать отступы в CoordinatorLayout вручную, см. setupForInsets функционировать в CoordinatorLayoutкласс. Для поддержки рисования за строкой состояния вы должны установитьandroid:fitsSystemWindows="true" за CoordinatorLayout:

<androidx.coordinatorlayout.widget.CoordinatorLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"    
  android:id="@+id/book_activity_root"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:animateLayoutChanges="true"
  tools:context="com.bookcrossing.mobile.ui.bookpreview.BookActivity"
  >

И как я понимаю вам не нужно animateLayoutChangesВот. Он отвечает за анимацию при изменении макета, например, удаление / добавление и отображение / скрытие представлений.

android:fitsSystemWindows="true"

Другие вопросы по тегам