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

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

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

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

ОграничениеLayout

Лучший способ создать адаптивный макет — использовать 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 . В этом примере, если окно достаточно велико (ширина не менее 580 dp) для отображения обоих представлений, панели отображаются рядом. Но если ширина окна меньше 580 dp, панели скользят друг по другу, занимая по отдельности все окно приложения.

Если ширина окна больше, чем общая заданная минимальная ширина (580dp), значения layout_weight можно использовать для пропорционального изменения размера двух панелей. В этом примере ширина панели списка всегда составляет 280 dp, поскольку она не имеет веса. Однако панель детализации всегда заполняет любое горизонтальное пространство за пределами 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-дюймовый планшет (600 x 1024 mdpi)
  • 720dp: 10-дюймовый планшет (720x1280 mdpi, 800x1280 mdpi и т. д.)

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

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

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

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

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

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

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 для экранов с высотой экрана не менее 600 dp.

Классификаторы ориентации

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

Для этого вы можете добавить квалификаторы 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 для доступа к устройствам в центре обработки данных Google.

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