Отзывчивый/адаптивный дизайн с видами

Попробуйте способ создания композиций.
Jetpack Compose — это рекомендуемый набор инструментов для создания пользовательского интерфейса для Android. Узнайте, как работать с адаптивными макетами в Compose.

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

Адаптивный дизайн

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

ConstraintLayout

Лучший способ создать адаптивный макет — использовать ConstraintLayout в качестве базового макета для вашего пользовательского интерфейса. ConstraintLayout позволяет задавать положение и размер каждого элемента в соответствии с пространственными отношениями с другими элементами макета. Таким образом, все элементы могут перемещаться и изменять размер одновременно по мере изменения отображаемого пространства.

Самый простой способ создать макет с помощью ConstraintLayout — использовать редактор макетов в Android Studio. Редактор макетов позволяет перетаскивать новые элементы в макет, применять ограничения относительно родительских и соседних элементов, а также задавать свойства элементов — и всё это без ручного редактирования XML-кода.

Рисунок 3. Редактор макетов в Android Studio, демонстрирующий ConstraintLayout .

Для получения дополнительной информации см. раздел «Создание адаптивного пользовательского интерфейса с помощью ConstraintLayout» .

Адаптивная ширина и высота

Чтобы обеспечить адаптивность макета к различным размерам экрана, используйте wrap_content , match_parent или 0dp (match constraint) для ширины и высоты компонентов представления вместо жестко заданных значений:

  • wrap_content : Размер представления устанавливается таким образом, чтобы он соответствовал содержимому представления.
  • match_parent : Представление максимально расширяется внутри родительского представления.
  • 0dp (match constraint) : В ConstraintLayout , аналогично match_parent . Представление занимает все доступное пространство в пределах ограничений представления.

Например:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/lorem_ipsum" />

На рисунке 4 показано, как ширина и высота TextView изменяются в зависимости от ширины экрана и ориентации устройства.

Рисунок 4. Адаптивный TextView .

TextView задает свою ширину так, чтобы она заполняла все доступное пространство ( match_parent ), и свою высоту точно так, как требуется высотой содержащегося в нем текста ( wrap_content ), что позволяет представлению адаптироваться к различным размерам экрана и различному количеству текста.

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

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

Адаптивный дизайн

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

SlidingPaneLayout для интерфейсов типа «список-детали».

Интерфейс «список-подробности» обычно обеспечивает разный пользовательский опыт на экранах разных размеров. На больших экранах панели списка и подробной информации обычно располагаются рядом. При выборе элемента в списке информация об элементе отображается в панели подробной информации без изменения интерфейса — две панели остаются рядом. Однако на маленьких экранах две панели отображаются отдельно, каждая занимает всю область экрана. При выборе элемента в панели списка панель подробной информации (содержащая информацию о выбранном элементе) заменяет панель списка. Нажатие кнопки «Назад» заменяет панель подробной информации списком.

SlidingPaneLayout управляет логикой определения того, какой из двух вариантов пользовательского интерфейса подходит для текущего размера окна:

<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
    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"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/item_navigation" />

</androidx.slidingpanelayout.widget.SlidingPaneLayout>

Атрибуты layout_width и layout_weight двух элементов, содержащихся в SlidingPaneLayout определяют поведение SlidingPaneLayout . В примере, если окно достаточно большое (ширина не менее 580dp), чтобы отобразить оба элемента, панели отображаются рядом. Но если ширина окна меньше 580dp, панели сдвигаются друг относительно друга, занимая по отдельности все окно приложения.

Если ширина окна превышает заданную минимальную ширину (580dp), значения layout_weight можно использовать для пропорционального изменения размеров двух панелей. В примере панель списка всегда имеет ширину 280dp, поскольку у нее нет параметра weight. Однако панель с подробной информацией всегда заполняет любое горизонтальное пространство, превышающее 580dp, из-за параметра layout_weight представления.

Альтернативные варианты оформления

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

Рисунок 5. Одно и то же приложение с различными макетами для разных размеров экрана.

Вы можете создавать адаптивные макеты, специфичные для каждого экрана, путем создания дополнительных каталогов res/layout/ в исходном коде вашего приложения. Создайте каталог для каждой конфигурации экрана, требующей разного макета. Затем добавьте к имени каталога layout квалификатор конфигурации экрана (например, layout-w600dp для экранов с доступной шириной 600dp).

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

Чтобы создать альтернативные макеты в Android Studio, см. раздел «Использование вариантов макета для оптимизации под разные экраны» в руководстве «Разработка пользовательского интерфейса с помощью представлений» .

Квалификатор наименьшей ширины

Квалификатор "минимальная ширина экрана" позволяет задавать альтернативные варианты компоновки для дисплеев, минимальная ширина которых измеряется в пикселях, не зависящих от плотности (dp).

Описывая размер экрана в единицах dp, Android позволяет создавать макеты, разработанные для конкретных размеров дисплея, без учета различной плотности пикселей.

Например, вы можете создать макет с именем main_activity , оптимизированный для телефонов и планшетов, создав разные версии файла в разных каталогах:

res/layout/main_activity.xml           # For phones (smaller than 600dp smallest width)
res/layout-sw600dp/main_activity.xml   # For 7" tablets (600dp wide or wider)

Квалификатор "наименьшая ширина" указывает наименьшую из двух сторон дисплея, независимо от текущей ориентации устройства, поэтому это способ указать общий размер дисплея, доступный для вашей компоновки.

Вот как другие наименьшие значения ширины соответствуют типичным размерам экранов:

  • 320dp: Небольшой экран телефона (240x320 ldpi, 320x480 mdpi, 480x800 hdpi и т. д.)
  • 480dp: Большой экран телефона ~5 дюймов (480x800 mdpi)
  • 600dp: 7-дюймовый планшет (600x1024 MDPI)
  • 720dp: 10-дюймовый планшет (720x1280 mdpi, 800x1280 mdpi и т. д.)

На следующем рисунке более подробно показано, как различные значения ширины экрана (dp) соответствуют различным размерам и ориентациям экрана.

Рисунок 6. Рекомендуемые значения ширины для поддержки различных размеров экрана.

Значения для наименьшего параметра ширины равны dp, поскольку важен объем доступного экранного пространства после учета системой плотности пикселей (а не исходного разрешения пикселей).

Размеры, которые вы указываете с помощью квалификаторов ресурсов, таких как "наименьшая ширина" , не являются фактическими размерами экрана . Скорее, эти размеры определяют ширину или высоту в единицах dp, доступных для окна вашего приложения . Система Android может использовать часть экрана для системного интерфейса (например, системную панель внизу экрана или строку состояния вверху), поэтому часть экрана может быть недоступна для вашего макета. Если ваше приложение используется в многооконном режиме, оно имеет доступ только к размеру окна, содержащего приложение. При изменении размера окна происходит изменение конфигурации с новым размером окна, что позволяет системе выбрать подходящий файл макета. Таким образом, квалификаторы ресурсов sizes, которые вы объявляете, должны указывать только пространство, необходимое вашему приложению. Система учитывает любое пространство, используемое системным интерфейсом, при предоставлении места для вашего макета.

Доступный квалификатор ширины

Вместо того чтобы изменять макет в зависимости от минимальной ширины дисплея, вы можете изменить его в зависимости от доступной ширины или высоты. Например, вы можете использовать двухпанельный макет, если ширина экрана составляет не менее 600dp, что может меняться в зависимости от того, находится ли устройство в альбомной или портретной ориентации. В этом случае следует использовать указание доступной ширины следующим образом:

res/layout/main_activity.xml         # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # For 7" tablets or any screen with 600dp available width
                                     # (possibly landscape phones)

Если для вашего приложения важна доступная высота, вы можете использовать квалификатор доступной высоты . Например, layout-h600dp для экранов с высотой не менее 600dp.

Квалификационные мероприятия по ознакомлению с программой обучения

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

Для этого вы можете добавить к именам каталогов макетов квалификаторы port или land . Просто убедитесь, что квалификаторы ориентации идут после квалификаторов размера. Например:

res/layout/main_activity.xml                # For phones
res/layout-land/main_activity.xml           # For phones in landscape
res/layout-sw600dp/main_activity.xml        # For 7" tablets
res/layout-sw600dp-land/main_activity.xml   # For 7" tablets in landscape

Для получения более подробной информации обо всех параметрах конфигурации экрана см. раздел «Обзор ресурсов приложения» .

Классы размеров окон

Классы размеров окна — это контрольные точки области просмотра, которые помогают создавать адаптивные макеты. Контрольные точки определяют доступную для вашего приложения область отображения как компактную , среднюю или расширенную . Ширина и высота указываются отдельно, поэтому ваше приложение всегда имеет класс размера окна для ширины и класс размера окна для высоты.

Для программного применения адаптивных макетов выполните следующие действия:

  • Создавайте ресурсы макета на основе контрольных точек класса размера окна.
  • Вычислите размеры окна вашего приложения по ширине и высоте, используя функцию WindowSizeClass#compute() из библиотеки Jetpack WindowManager.
  • Расширить ресурс макета для текущих классов размеров окна.

Для получения более подробной информации см. раздел «Классы размеров окон» .

Модульные компоненты пользовательского интерфейса с использованием фрагментов

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

Например, шаблон «список-подробности» (см. SlidingPaneLayout выше) можно реализовать с помощью одного фрагмента, содержащего список, и другого фрагмента, содержащего подробные сведения об элементах списка. На больших экранах фрагменты можно отображать рядом, на маленьких — по отдельности, заполняя весь экран.

Для получения более подробной информации см. обзор фрагментов .

Встраивание активности

Если ваше приложение состоит из нескольких активностей, встраивание активностей позволяет легко создать адаптивный пользовательский интерфейс.

Встраивание действий позволяет отображать несколько действий или несколько экземпляров одного и того же действия одновременно в окне задач приложения. На больших экранах действия могут отображаться рядом друг с другом; на маленьких экранах — друг над другом.

Способ отображения действий в приложении определяется путем создания XML-файла конфигурации, который система использует для определения соответствующего отображения в зависимости от размера экрана. В качестве альтернативы можно использовать вызовы API Jetpack WindowManager .

Функция встраивания активности поддерживает изменение ориентации устройства, а также работу со складными устройствами, позволяя выполнять действия по складыванию и раскладыванию устройства при его вращении, складывании и раскладывании.

Для получения более подробной информации см. раздел «Встраивание действий» .

Размеры экрана и соотношение сторон

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

Android 10 (уровень API 29) и более поздние версии поддерживают широкий диапазон соотношений сторон. Форм-факторы складных устройств могут варьироваться от высоких и узких экранов, например, 21:9 в сложенном состоянии, до квадратных экранов с соотношением сторон 1:1 в разложенном состоянии.

Для обеспечения совместимости с как можно большим количеством устройств протестируйте свои приложения на как можно большем количестве следующих соотношений сторон экрана:

Рисунок 7. Различные соотношения сторон экрана.

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

Если вы предпочитаете тестировать на реальном устройстве, но у вас его нет, вы можете использовать Firebase Test Lab для доступа к устройствам в центре обработки данных Google.

Дополнительные ресурсы