Пользовательский интерфейс

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

Тема

Предлагаемая нами тема оформления Glass обладает следующими характеристиками:

  • Отображает действия в полноэкранном режиме без панели действий.
  • Применяет сплошной черный фон.
  • Осветляет цвет для эффекта цветового края.
  • Применяет белый цвет текста.

Ниже приведены рекомендуемые настройки темы для Glass:

 <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
   <item name="android:windowBackground">@android:color/black</item>
   <item name="android:colorEdgeEffect">@android:color/white</item>
   <item name="android:textColor">@android:color/white</item>
 </style>

XML-макеты

Вот два основных варианта расположения карт, которые могут быть созданы с помощью ваших фрагментов:

Основная планировка

Этот макет определяет рекомендуемые стандартные отступы и нижний колонтитул для карточки. Разместите свои собственные элементы в пустом FrameLayout .

Центральный блок занимает большую часть внутреннего пространства экрана размером 560 на 240 пикселей, с небольшой полосой внизу размером 560 на 40 пикселей. Также имеются четыре небольших блока размером 40 на 40 пикселей, по одному в каждом углу.

Вот пример XML-разметки:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <FrameLayout
      android:id="@+id/body_layout"
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_margin="@dimen/glass_card_margin"
      app:layout_constraintBottom_toTopOf="@id/footer"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent">

    <!-- Put your widgets inside this FrameLayout. -->

  </FrameLayout>

  <!-- The footer view will grow to fit as much content as possible while the
         timestamp view keeps its width. If the footer text is too long, it
         will be ellipsized with a 40dp margin between it and the timestamp. -->

  <TextView
      android:id="@+id/footer"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="@dimen/glass_card_margin"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toStartOf="@id/timestamp"
      app:layout_constraintStart_toStartOf="parent" />

  <TextView
      android:id="@+id/timestamp"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAlignment="viewEnd"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Расположение в левой колонке

Этот макет определяет левую колонку шириной в одну треть и правую колонку шириной в две трети в виде двух классов FrameLayout , в которые вы можете поместить свои представления. Пример показан на следующем рисунке.

На изображении показана левая колонка размером 240 на 360 пикселей, которая смещает основной макет. Ее размер сжимается, чтобы поместиться, основная область составляет 330 на 240 пикселей, с небольшой нижней полосой размером 330 на 40 пикселей. В двух правых углах расположены два маленьких прямоугольника размером 40 на 40 пикселей, и есть еще четыре прямоугольника размером 30 на 40 пикселей, два в нижних углах левой колонки и два слева от основного макета, один сверху и один снизу.

Вот пример XML-разметки:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <FrameLayout
      android:id="@+id/left_column"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:background="#303030"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintWidth_percent=".333">

    <!-- Put widgets for the left column inside this FrameLayout. -->

  </FrameLayout>

  <FrameLayout
      android:id="@+id/right_column"
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_marginTop="@dimen/glass_card_two_column_margin"
      android:layout_marginStart="@dimen/glass_card_two_column_margin"
      android:layout_marginBottom="@dimen/glass_card_two_column_margin"
      android:layout_marginEnd="@dimen/glass_card_margin"
      app:layout_constraintBottom_toTopOf="@id/footer"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toEndOf="@id/left_column"
      app:layout_constraintTop_toTopOf="parent">

    <!-- Put widgets for the right column inside this FrameLayout. -->

  </FrameLayout>

  <!-- The footer view will grow to fit as much content as possible while the
         timestamp view keeps its width. If the footer text is too long, it
         will be ellipsized with a 40dp margin between it and the timestamp. -->

  <TextView
      android:id="@+id/footer"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="@dimen/glass_card_margin"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toStartOf="@id/timestamp"
      app:layout_constraintStart_toEndOf="@id/left_column" />

  <TextView
      android:id="@+id/timestamp"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginEnd="@dimen/glass_card_margin"
      android:layout_marginBottom="@dimen/glass_card_margin"
      android:ellipsize="end"
      android:singleLine="true"
      android:textAlignment="viewEnd"
      android:textAppearance="?android:attr/textAppearanceSmall"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Стандартные размеры

Используйте следующие элементы в сочетании с предыдущими макетами или вашими собственными макетами, чтобы создать файл, соответствующий стандартному стилю Glass. Создайте этот файл как res/values/dimens.xml в вашем проекте Android.

<?xml version="1.0" encoding="utf-8"?>
<resources>

  <!-- The recommended margin for the top, left, and right edges of a card. -->
  <dimen name="glass_card_margin">40dp</dimen>

  <!-- The recommended margin between the bottom of the card and the footer. -->
  <dimen name="glass_card_footer_margin">50dp</dimen>

  <!-- The recommended margin for the left column of the two-column card. -->
  <dimen name="glass_card_two_column_margin">30dp</dimen>

</resources>

Мы рекомендуем использовать RecyclerView для создания меню. Они должны основываться на стандартном файле меню Android из ресурсов проекта Android Studio. Android позволяет переопределить стандартное создание меню и заменить его вашей реализацией. Для этого выполните следующие шаги:

  1. Создайте макет с помощью RecyclerView и установите его в качестве представления для вашей Activity .
  2. Настройте RecyclerView и его адаптер на использование только что созданной коллекции пунктов меню.
  3. Переопределите метод onCreateOptionsMenu .
    1. Расширьте свое меню и добавьте новый элемент в коллекцию для каждого пункта меню.
    2. Вызовите метод notifyDataSetChanged адаптера.

    Котлин

        override fun onCreateOptionsMenu(menu: Menu): Boolean {
            val menuResource = intent
                .getIntExtra(EXTRA_MENU_KEY, EXTRA_MENU_ITEM_DEFAULT_VALUE)
            if (menuResource != EXTRA_MENU_ITEM_DEFAULT_VALUE) {
                menuInflater.inflate(menuResource, menu)
                for (i in 0 until menu.size()) {
                    val menuItem = menu.getItem(i)
                    menuItems.add(
                        GlassMenuItem(
                            menuItem.itemId, menuItem.icon,
                            menuItem.title.toString()
                        )
                    )
                    adapter.notifyDataSetChanged()
                }
            }
            return super.onCreateOptionsMenu(menu)
        }
        

    Java

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
          final int menuResource = getIntent()
              .getIntExtra(EXTRA_MENU_KEY, EXTRA_MENU_ITEM_DEFAULT_VALUE);
          if (menuResource != EXTRA_MENU_ITEM_DEFAULT_VALUE) {
            final MenuInflater inflater = getMenuInflater();
            inflater.inflate(menuResource, menu);
    
            for (int i = 0; i < menu.size(); i++) {
              final MenuItem menuItem = menu.getItem(i);
              menuItems.add(
                  new GlassMenuItem(menuItem.getItemId(), menuItem.getIcon(),
                      menuItem.getTitle().toString()));
              adapter.notifyDataSetChanged();
            }
          }
          return super.onCreateOptionsMenu(menu);
        }
        
  4. Используйте OnScrollListener вместе с LayoutManager и SnapHelper , чтобы определить, какой вариант был выбран.
  5. Для обработки события выбора пункта меню необходимо дождаться жеста TAP .
  6. Создайте Intent , содержащий информацию о выбранном пункте меню.
  7. Задайте результат для этого действия и завершите его.
  8. Вызовите startActivityForResult из фрагмента или активности, где вы хотите отобразить меню. Для этого используйте жест TAP .
  9. Переопределите метод onActivityResult в вызывающем фрагменте или активности, чтобы обработать выбранный пункт меню.

Руководящие принципы

Ниже приведён список рекомендаций по настройке макета меню:

На следующем изображении представлен пример настраиваемого макета меню:

На этом простом изображении показан черный фон со словами «Расположение меню», расположенными по центру экрана, и символом телефона рядом.

Для получения подробной информации о реализации ознакомьтесь с примером приложения Card .

Страницы с возможностью пролистывания

Стеклянный дисплей и сенсорная панель работают вместе, обеспечивая удобное отображение карточек с возможностью пролистывания. Вы можете создавать страницы с возможностью пролистывания в своем приложении, используя стандартный API Android ViewPager .

Для получения дополнительной информации о том, как использовать Android ViewPager для прокрутки карточек или экранов, посетите документацию по обучению работе со слайдами на экране .