Как заставить контент отображаться за панелью инструментов не полной ширины (например, в новом приложении Gmail или Google)

#android #android-layout #android-toolbar #android-appbarlayout

#Android #android-макет #android-панель инструментов #android-coordinatorlayout #android-appbarlayout

Вопрос:

То, что я пытаюсь реализовать, — это панель инструментов, которая не имеет полной ширины (имеет поле со всех сторон 16dp), как показано ниже:

Gmail — Обратите внимание, что RecyclerView можно увидеть прокрутку за панелью инструментов Gmail

Приложение Google — то же самое, карточки видны за панелью инструментов. Приложение Google

Кроме того, эти панели инструментов скрываются при прокрутке вниз и появляются при прокрутке вверх.

Содержимое панели инструментов — это не то, о чем я беспокоюсь прямо сейчас.

Я предполагаю, что это делается с использованием макета координатора, так что это скелет, который у меня есть:

  • Макет координатора
    • AppBarLayout
      • Панель инструментов
    • Вложенный просмотр прокрутки (appbar_scrolling_view_behavior)
      • ConstraintLayout
 <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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    tools:context=".MainContentFragment">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_margin="32dp"
        android:background="@android:color/transparent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@android:color/holo_red_dark"
            app:layout_scrollFlags="scroll|enterAlways">


        </androidx.appcompat.widget.Toolbar>

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        ...
  

Это вывод перед прокруткой
вывод

И после прокрутки вниз вывод2

Как вы можете видеть, пространство за пределами панели инструментов непрозрачно, но имеет этот серый фон, поскольку содержимое находится под ним и его нельзя увидеть.

Ответ №1:

Идея отображения содержимого за панелью инструментов:

  1. Установка отрицательного поля для просмотра прокрутки ( NestedScrollView / RecyclerView ), которое соответствует желаемому размеру пустой области при прокрутке всего содержимого вверх (все, что находится под панелью инструментов, ничего позади); предполагается -100dp в приведенной ниже демонстрации

  2. Верните обратно это отрицательное поле для дочернего элемента NestedScrollView (в макете) или 1-го дочернего элемента RecyclerView (программно)

  3. Поместите вид прокрутки поверх AppBarLayout так, чтобы фон AppBarLayout не закрывал содержимое прокрутки, чтобы они отображались в задней части панели инструментов.

Косметика:

  • Удалите значение AppBarLayout до 0, чтобы сделать его несуществующим; есть только панель инструментов.
  • Установите цвет фона AppBarLayout на прозрачный, так что теперь он принимает фон корневого макета.

ДЕМОНСТРАЦИЯ:

 
<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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="-100dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="100dp"
            android:text="@string/longText" />

    </androidx.core.widget.NestedScrollView>

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        app:elevation="0dp">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:background="@drawable/rounded_toolbar"
            app:layout_scrollFlags="scroll|enterAlways">

            <com.google.android.material.appbar.MaterialToolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin" />

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>
  

Для RecyclerView вы не можете управлять его дочерними элементами с помощью макетов, поэтому изменение поля можно либо с помощью

  • Имея 2 макета, один с верхним полем 100dp для первого дочернего элемента, другой без полей для остальных дочерних элементов. И решите, какой макет в адаптере onCreateViewHolder()
  • Добавление поля в поле адаптера onBindViewHolder() :
 @Override
public void onBindViewHolder(@NonNull CustomViewHolder holder, final int position) {

    ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) holder.itemView.getLayoutParams();
    if (position == 0) {
        Resources resources = holder.itemView.getContext().getResources();
        float dip = 100f;
        float px = TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP,
                dip,
                resources.getDisplayMetrics()
        );
        params.topMargin = (int) px;
    } else
        params.topMargin = 0;

    holder.itemView.setLayoutParams(params);
    
    //...... rest of code
}
  


Ответ №2:

Вы должны просто обернуть все виджеты внутри CoordinatorLayout с помощью FrameLayout и изменить AppBarLayout положение до конца:

 <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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    tools:context=".MainContentFragment">

    <FrameLayout android:layout_width="match_parent"
    android:layout_height="match_parent">


    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        ...


    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_margin="32dp"
        android:background="@android:color/transparent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@android:color/holo_red_dark"
            app:layout_scrollFlags="scroll|enterAlways">


        </androidx.appcompat.widget.Toolbar>

    </com.google.android.material.appbar.AppBarLayout>

    </FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout