界面

本文档将介绍如何遵循 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 布局

以下是 fragment 可以膨胀的两种基本卡片布局:

主布局

此布局定义了卡片的建议标准内边距和页脚。将您自己的视图放入空的 FrameLayout

中心框占据 560x240 像素的屏幕大部分空间,底部有一个小条(560x40 像素)。
另外还有四个较小的 40x40 像素块,每个角一个

以下是一个 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 x 360 像素显示左列,这会使主布局被推翻。其大小经过挤压后形成的主面积,主面积为 330 x 240 像素,并带有一个较小的下边条,即 330 x 40 像素。右侧两个角落有两个 40x40 像素的小框,还有四个其他的 30x40 像素框,分别位于左列的下角和主布局的左侧,一个位于顶部,另一个位于底部。

以下是一个 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 标准样式的文件。在 Android 项目中将此文件创建为 res/values/dimens.xml

<?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 Studio 项目资源中的标准 Android 菜单文件。Android 允许您替换标准菜单创建方式,并将其替换为您的实现。如需执行此项调整,请按照以下步骤操作:

  1. 使用 RecyclerView 创建布局,并将其设置为 Activity 的视图。
  2. RecyclerView 及其适配器设置为使用新创建的菜单项集合。
  3. 替换 onCreateOptionsMenu 方法。
    1. 膨胀菜单,并将新元素添加到每个菜单项的集合中。
    2. 对适配器调用 notifyDataSetChanged 方法。

    Kotlin

        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. OnScrollListenerLayoutManagerSnapHelper 结合使用,确定已选择哪个选项。
  5. 监听 TAP 手势以处理菜单项选择事件。
  6. 使用所选菜单项的相关信息创建 Intent
  7. 请为此活动设置结果并完成。
  8. 从包含菜单的 fragment 或 activity 调用 startActivityForResult。 为此,请使用 TAP 手势。
  9. 替换调用方 Fragment 或 Activity 中的 onActivityResult 以处理所选菜单项。

指南

下面列出了有关如何设置菜单布局的建议:

下图是自定义菜单布局的示例:

这张简单的图片显示了黑色背景,文字“菜单”布局在屏幕上居中,且手机符号相邻。

如需了解实现详情,请查看卡片示例应用

手滑式页面

Google Glass 和触控板搭配使用,方便显示可滑动的卡片。您可以使用标准的 Android ViewPager API 在 Activity 中构建手滑式页面。

如需详细了解如何使用 Android ViewPager 滚动浏览卡片或屏幕,请访问屏幕幻灯片培训文档。