本文档将介绍如何遵循 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
。
以下是一个 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
类的形式定义了左三分之一宽和右三分之三列,您可以将视图放入这两个类中。如需查看示例,请参考下图。
以下是一个 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 允许您替换标准菜单创建方式,并将其替换为您的实现。如需执行此项调整,请按照以下步骤操作:
- 使用
RecyclerView
创建布局,并将其设置为Activity
的视图。 - 将
RecyclerView
及其适配器设置为使用新创建的菜单项集合。 - 替换
onCreateOptionsMenu
方法。- 膨胀菜单,并将新元素添加到每个菜单项的集合中。
- 对适配器调用
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); }
- 将
OnScrollListener
与LayoutManager
和SnapHelper
结合使用,确定已选择哪个选项。 - 监听
TAP
手势以处理菜单项选择事件。 - 使用所选菜单项的相关信息创建
Intent
。 - 请为此活动设置结果并完成。
- 从包含菜单的 fragment 或 activity 调用
startActivityForResult
。 为此,请使用TAP
手势。 - 替换调用方 Fragment 或 Activity 中的
onActivityResult
以处理所选菜单项。
指南
下面列出了有关如何设置菜单布局的建议:
- 文字大小:
64sp
- 背景颜色:
#96000000
- 使用
64dpx64dp
大小的 Material 图标 - 将
windowIsTranslucent
主题标志设置为true
下图是自定义菜单布局的示例:
如需了解实现详情,请查看卡片示例应用。
手滑式页面
Google Glass 和触控板搭配使用,方便显示可滑动的卡片。您可以使用标准的 Android ViewPager
API 在 Activity 中构建手滑式页面。