为 Wear OS 构建表盘

1. 准备工作

如需为 Wear OS 创建表盘,开发者必须使用表盘格式 (WFF),这是一种基于 XML 的格式,可让您创建富有表现力且性能出众的表盘。

本 Codelab 面向希望使用 XML 手工制作表盘的用户,或希望更好地了解该格式以帮助他们构建自己的设计工具的用户。

如果您想使用图形工具创建自己的表盘,我们建议您查看 Watch Face Studio 等现有工具。

前提条件

  • 有 XML 方面的经验。

实践内容

在此 Codelab 中,您将学习:

  • WFF 表盘的打包方法
  • 如何创建包含微光模式的表盘
  • 添加形状等元素
  • 在表盘中整合数据源
  • 如何排查表盘问题

您将构建一个可自定义的表盘,其中包含可供选择的各种颜色主题、内置步数和日期指示器。

90468c36ea8b7ca.png 324c4462145dbcc6.png

所需条件

2. 了解表盘格式项目结构

下载 Codelab 文件

首先,请在此处下载 Codelab 文件

$ git clone https://github.com/android/codelab-watch-face-format

或者,您可以下载代码库 Zip 文件:

watch-face-format 目录中有两个项目:startfinish。我们将使用 start 项目,但您随时可以查看 finish 项目,其中包含完成的 Codelab。

我们来检查一下表盘格式项目的基本结构。您可以使用自己选择的编辑器,也可以在 Android Studio 中依次选择 File > Open… 并选择 start 目录,以打开 start 项目本身。

start/watchface/src/main 目录中,您将看到以下文件,我们来看看每个文件的作用:

文件

说明

AndroidManifest.xml

与常规 Android 应用一样,此文件包含有关表盘以及构建表盘所需内容的必要信息

res/xml/watch_face_info.xml

表盘信息文件包含有关表盘的元数据,例如如何查找预览图片以及表盘是否可自定义。

res/raw/watchface.xml

此文件包含表盘本身的定义。虽然可以有多个定义,但这是使用的默认文件。

res/drawable/preview.png

每个表盘都需要一个供系统使用的预览图片。为了构建此项目,start/ 文件夹中包含一个空白预览,我们稍后会对其进行更新

res/drawable/hour.pngres/drawable/minute.pngres/drawable/second.png

这些是将在表盘中使用的时针。

res/values/strings.xml

与 Android 应用一样,包含可在表盘中使用的字符串。

代码在哪里?

请注意,该项目中实际上并不包含任何代码。除了 AndroidManifest.xml 文件外,项目的所有文件都存放在 res/ 目录下,即资源目录。这是因为表盘格式的表盘不能包含任何代码。例如,如果您尝试添加 Kotlin 或 Java 代码,Play 商店将不会接受这样的表盘。

Wear OS 系统会读取这些资源,并负责为您构建和运行表盘。这意味着您无需编写任何运行时或其他逻辑代码,从而节省了开发工作量。

3. 为 Wear OS 构建表盘

我们将更新上述每个文件,以创建一个实用的表盘。

准备清单文件

为了将软件包标识为表盘格式的表盘,清单文件需要声明以下两点:

  1. 项目中不包含任何代码。
  2. 所使用的表盘格式版本。

首先,更新 <application> 元素,添加 hasCode 属性:

<application
    android:label="@string/watch_face_name"
    android:hasCode="false">

其次,在 <application> 元素中添加 <property>,以指定此表盘所使用的表盘格式版本:

<property
    android:name="com.google.wear.watchface.format.version"
    android:value="1" />

定义 watch_face_info 文件

watch_face_info.xml 文件有一项强制性要求:必须指定预览图片的位置。在此项目中,我们在 res/drawable/preview.png 下提供了预览图片。目前该文件为空,但后续我们会将其替换为已完成表盘的实际屏幕截图。

在本 Codelab 中,我们还将使表盘具备可自定义特性。我们还在 watch_face_info.xml file 中使用 <Editable> 元素声明来声明这一特性。

请更新 res/xml/watch_face_info.xml 文件,添加以下元素:

<Preview value="@drawable/preview" />
<Editable value="true" />

编写表盘格式的 XML 文件

实际表盘的定义包含在 res/raw/watchface.xml 文件中。请在编辑器中打开此文件查看。您会看到 <WatchFace> 元素为表盘定义了 450x450 的宽度和高度。在文件的其余部分都会使用这个坐标空间,并且无论表盘的实际像素尺寸是多少,都可以相应地进行缩放。

XML 内容如下:

<?xml version="1.0"?>
<WatchFace width="450" height="450">
  <Scene>
    <PartText x="0" y="0" width="450" height="450">
      <Text>
        <Font family="SYNC_TO_DEVICE" size="48">Hello, World!</Font>
      </Text>
    </PartText>
  </Scene>
</WatchFace>

目前,这个定义只会让手表上显示“Hello, World!”,暂时还未实现时间显示功能!不过,我们稍后会回来解决这个问题。接下来,我们将构建表盘并将其部署到设备上。

构建和部署表盘

在命令行界面中,请确保您当前位于 start 目录,然后执行以下命令:

./gradlew installDebug

或者,在 Windows 系统中,运行以下命令:

gradlew.bat installDebug

这将构建表盘并将其安装到设备上。长按表盘屏幕,找到 Codelab 表盘。或者,如需通过命令行设置表盘,请使用以下命令:

adb shell am broadcast -a com.google.android.wearable.app.DEBUG_SURFACE --es operation set-watchface --es watchFaceId com.example.codelab

现在,您应该能在手表或模拟器上看到表盘了!恭喜!

b1ab1ed6a1ce8575.png

4. 添加时间

表盘格式支持显示模拟时钟和数字时钟,您甚至可以在一个表盘上同时显示两种或多种时钟。

我们来看看如何使用 < AnalogClock> 元素添加模拟时钟。首先,从 watchface.xml 文件中移除整个 < PartText> 元素,并将其替换为以下代码:

<AnalogClock x="0" y="0" width="450" height="450">
  <!-- TODO: Add shadows here later -->
  <HourHand resource="hour"
      x="215" y="50" width="20" height="190"
      pivotX="0.5" pivotY="0.921" >
  </HourHand>
  <MinuteHand resource="minute"
      x="217" y="25" width="16" height="220"
      pivotX="0.5" pivotY="0.9">
  </MinuteHand>
  <SecondHand resource="second"
      x="221" y="15" width="8" height="245"
      pivotX="0.5" pivotY="0.857">
    <Variant mode="AMBIENT" target="alpha" value="0" />
    <Sweep frequency="15" />
  </SecondHand>
</AnalogClock>

<AnalogClock> 元素的高度和宽度均为 450,因此它占据了整个屏幕。它还有三个子元素:< HourHand>< MinuteHand>< SecondHand>。请注意以下关于这些子元素的定义方式:

  • 资源:这些子元素都包含一个资源属性,该属性指向一个可绘制的资源文件。例如,在 res/drawable 目录下有一个 hour.png 文件,该文件由 <HourHand> 元素使用。请注意,在这里无需指定 @drawable
  • 轴点:指针会自动旋转,而 pivotXpivotY 属性则用于指定旋转的轴点位置。例如,pivotY 的值是通过以下方式计算的:

f08428ae204605e1.png

c194bd487cebbe26.png

  • 变体<SecondHand> 元素包含一个 < Variant> 子元素,该子元素的作用是隐藏秒针,因为在微光模式下,表盘仅每分钟更新一次。

现在,运行以下命令来重新构建表盘并将其部署到您的设备或模拟器上:

./gradlew installDebug

现在,我们已经实现了时钟的基本功能,但仍有很多可以改进的地方!

52628bf6c0d30d09.png

5. 添加颜色和主题

表盘之所以有趣,部分原因在于您可以对其进行个性化设置,让它更具表现力。

目前,我们的表盘设计略显单调,完全是白的。因此,我们来为它增添一些色彩吧!不仅如此,我们还要让用户能够自定义色彩主题。

创建 ColorConfiguration

首先,我们将定义表盘中可用的色彩主题。在 watchface.xml 文件中,找到文本 <!-- TODO: Add UserConfigurations here --> 并将其替换为:

<UserConfigurations>
  <ColorConfiguration id="themeColor" displayName="color_label" defaultValue="0">
    <ColorOption id="0" displayName="color_theme_0" colors="#ffbe0b #fb5607 #ff006e #8338ec #883c3c3c" />
    <ColorOption id="1" displayName="color_theme_1" colors="#8ecae6 #219ebc #ffb703 #fb8500 #883c3c3c" />
    <ColorOption id="2" displayName="color_theme_2" colors="#ff595e #ffca3a #8ac926 #1982c4 #883c3c3c" />
    <ColorOption id="3" displayName="color_theme_3" colors="#ff0000 #00ff00 #ff00ff #00ffff #883c3c3c" />
    <ColorOption id="4" displayName="color_theme_4" colors="#ff99c8 #fcf6bd #d0f4de #a9def9 #883c3c3c" />
    <ColorOption id="5" displayName="color_theme_5" colors="#1be7ff #6eeb83 #e4ff1a #ffb800 #883c3c3c" />
  </ColorConfiguration>
</UserConfigurations>

这段代码定义了 6 种色彩主题,每种主题包含 5 种颜色。每个主题的颜色列表以空格分隔,如 colors 属性所示。

为了方便用户理解,每个主题都需要一个直观的名称。因此,请将以下定义添加到 res/values/strings.xml 文件中:

<string name="color_label">Color Theme</string>
<string name="color_theme_0">Bold</string>
<string name="color_theme_1">Magic</string>
<string name="color_theme_2">Breeze</string>
<string name="color_theme_3">Daytime</string>
<string name="color_theme_4">Relaxed</string>
<string name="color_theme_5">Smart</string>

使用 ColorConfiguration

定义色彩主题后,通过为每个表针添加 tintColor 属性,将这些颜色应用到表针上。将 watchface.xml 文件修改如下:

<HourHand ... tintColor="[CONFIGURATION.themeColor.0]">
...
<MinuteHand ... tintColor="[CONFIGURATION.themeColor.1]">
...
<SecondHand ... tintColor="[CONFIGURATION.themeColor.2]">

<HourHand> 引用所选主题中的第一种颜色,<MinuteHand> 引用第二种颜色,<SecondHand> 则引用第三种颜色。

按照之前的方法重新构建并部署表盘,您会发现它现在已经是彩色的了!

e382aaf41c7990d9.png

不仅如此,如果您长按表盘并点按设置按钮,还可以从 6 种色彩主题中进行选择!

79ffac91f7cabaf5.png

6. 添加背景颜色

我们还可以采取一些措施,让这款表盘脱颖而出。接下来,我们添加一个醒目的背景设计。尽管背景主要保持为黑色,但这种色彩点缀能够提升整体视觉效果。

我们将使用表盘格式的 < PartDraw> 元素,该元素允许您创建一个图层,用于绘制线条、矩形、椭圆和弧线等基本图形。将文本 <!-- TODO: Add the background design here --> 替换为以下内容:

<Group x="100" y="100" width="250" height="250" name="background" alpha="127">
  <Variant mode="AMBIENT" target="alpha" value="0" />
  <PartDraw x="0" y="0" width="250" height="250">
    <Ellipse x="0" y="0" width="250" height="250">
      <Fill color="[CONFIGURATION.themeColor.3]" />
    </Ellipse>
    <Ellipse x="50" y="50" width="150" height="150">
      <Fill color="#000000" />
    </Ellipse>
  </PartDraw>
</Group>

请注意我们再次使用了 <Variant> 元素:在微光模式下,这将移除背景环,从而减少点亮的像素数量。

此外,我们再次利用色彩主题来选择背景环的颜色,从而确保表盘上所有元素的样式保持一致。

710c8969df19226b.png

7. 验证表盘

在进一步增强表盘功能之前,我们先来探讨如何利用表盘格式验证器简化开发流程。

验证器是一个用于检查 XML 文件正确性的工具,它能帮助您节省时间,避免在构建和部署表盘后才发现表盘无法正常运行。

  1. 从 GitHub 代码库下载验证器 JAR 文件
  2. 针对 watchface.xml 文件运行该验证器
java -jar wff-validator.jar 1 watchface/src/main/res/raw/watchface.xml

如果表盘 XML 文件有效,您将看到确认消息;但是,如果发现错误,系统会显示错误的详细信息及其位置,例如:

SEVERE: [Line 18:Column 49]: cvc-complex-type.2.4.a: Invalid content was found starting with element 'PartDrw'

8. 使用数据源

表盘格式支持利用多种不同的数据源,让您的表盘更加实用。

接下来,我们将添加两个常用的数据源,以增强表盘的实用性:当前日期(毕竟谁都有忘记日期的时候)和每日步数。

这些元素中都放置在 < PartText> 容器中,该容器是一个用于执行文本操作的层。

添加日期

<!-- TODO: Add the date/time element here --> 文本替换为以下内容:

<PartText x="225" y="225" width="225" height="225">
  <Variant mode="AMBIENT" target="alpha" value="0" />
  <TextCircular centerX="0" centerY="0" width="415" height="415" startAngle="180" endAngle="90" align="CENTER" direction="COUNTER_CLOCKWISE">
    <Font family="SYNC_TO_DEVICE" size="28" color="[CONFIGURATION.themeColor.0]">
      <Template>
        <![CDATA[%d %s]]>
        <Parameter expression="[DAY]"/>
        <Parameter expression="[MONTH_S]"/>
      </Template>
    </Font>
  </TextCircular>
</PartText>

在上面的代码段中,我们使用 < Template> 将两个数据源格式化为字符串。DAY 是一个介于 1 到 31 之间的整数,而 MONTH_S 已经是字符串,因此我们使用格式化表达式 %d %s 将整数和字符串放在一起。

最佳实践是将其用 CDATA 元素包裹起来,这样可以避免在显示过程中意外引入空格,进而影响元素的定位和对齐。

最后,请再次注意,我们再次使用了色彩主题,以确保表盘上的最新添加项与现有主题保持一致。

添加步数

<!-- TODO: Add the step count element here --> 文本替换为以下内容:

<PartText x="0" y="0" width="225" height="225">
  <Variant mode="AMBIENT" target="alpha" value="0" />
  <TextCircular centerX="225" centerY="225" width="415" height="415" startAngle="270" endAngle="360" align="CENTER" direction="CLOCKWISE">
    <Font family="SYNC_TO_DEVICE" size="28" color="[CONFIGURATION.themeColor.2]">
      <Template>
        <![CDATA[%05d]]>
        <Parameter expression="[STEP_COUNT]"/>
      </Template>
    </Font>
  </TextCircular>
</PartText>

表盘格式支持各种不同的数据源,而步数则是任何表盘的绝佳补充,它能让用户轻松跟踪自己的日常活动和锻炼情况。

构建并部署表盘,查看这些最新添加的内容:

78cd5888c9e3a9a6.png

9. 收尾工作和预览

在设计表盘时,细节至关重要。因此,我们再添加一些最终的修饰,让表盘更加完美。

向表盘添加阴影

表盘上的指针颜色各异,搭配得相得益彰,但在表盘上略显平淡。将 <!-- TODO: Add shadows here later --> 替换为以下内容,为表针添加阴影效果:

<HourHand resource="hour" x="220" y="55" width="20" height="190"
    pivotX="0.5" pivotY="0.921" tintColor="[CONFIGURATION.themeColor.4]">
  <Variant mode="AMBIENT" target="alpha" value="0" />
</HourHand>
<MinuteHand resource="minute" x="222" y="30" width="16" height="220"
    pivotX="0.5" pivotY="0.9" tintColor="[CONFIGURATION.themeColor.4]">
  <Variant mode="AMBIENT" target="alpha" value="0" />
</MinuteHand>
<SecondHand resource="second" x="226" y="20" width="8" height="245"
    pivotX="0.5" pivotY="0.857" tintColor="[CONFIGURATION.themeColor.4]">
  <Variant mode="AMBIENT" target="alpha" value="0" />
  <Sweep frequency="15" />
</SecondHand>

8b5959083acc5689.png

每个知名手表品牌都会在其表盘上展示独特的徽标,我们也来为表盘增添一份个性吧!当然,我们可以选择使用 Android 徽标!

但是,考虑到这是智能手表,我们可以尝试一些创新,比如添加一个能根据佩戴者手腕角度移动的徽标。

为实现这一效果,我们将图片放置在 < Group> 元素中,然后使用 < Transform> 元素根据手腕角度为 <Group> 元素应用旋转。具体结构如下:

e738ca09c695ca93.png

元素的默认旋转中心位于其中心点,因此我们无需调整 <Group>pivotXpivotY 属性。将 <Transform> 应用于 <Group> 后,<PartImage> 将围绕该中心点旋转。

<Transform> 中,我们使用 [ ACCELEROMETER_ANGLE_XY] 数据源,它表示 X 方向和 Y 方向的角度之和。

<!-- TODO: Add the Android logo --> 替换为以下代码段:

<Group x="92" y="92" width="266" height="266" name="logo_container">
  <Variant mode="AMBIENT" target="alpha" value="0" />
  <Transform target="angle" mode="BY" value="0.1 * [ACCELEROMETER_ANGLE_XY]" />
  <PartImage x="97" y="0" width="72" height="72"
    tintColor="[CONFIGURATION.themeColor.2]">
    <Image resource="android"/>
  </PartImage>
</Group>

重新部署表盘。如果您使用的是实体设备,请将其佩戴在手腕上,并左右摆动手腕,观察 Android 徽标如何移动!如果您使用的是模拟器,请打开扩展的模拟器控件,并在虚拟传感器中调整 X 和 Y 角度。

更新预览

还记得在本 Codelab 的开头,我们提到的 preview.png 文件吗?系统会使用该文件来显示表盘预览。现在,让我们更新此文件,以更好地展示我们完成的表盘!

生成屏幕截图最简单的方法是使用模拟器。在表盘运行时,点击屏幕截图按钮:

6172ea8cc9309516.png

确保截图设置为显示形状

9d90300c3ce4d8f.png

保存图片,并用此新图片替换 res/drawable/preview.png 文件。然后,像之前一样重新构建和部署表盘。

10. 恭喜

恭喜!您已经学习了使用表盘格式创建表盘的基础知识!

此 Codelab 的解决方案

您可以从 GitHub 获取本 Codelab 的解决方案代码:

$ git clone https://github.com/android/codelab-watch-face-format

或者,您可以下载代码库 Zip 文件:

后续操作

表盘格式的功能远不止于此。以下是一些建议,供您进一步探索:

增强表盘功能

准备发布

  • 请查看内存占用工具,该工具可分析表盘的内存使用情况,是您在将表盘上传到 Google Play 之前不可或缺的辅助工具!