如需开始在应用中提供卡片,请在应用的 build.gradle
文件中添加以下依赖项。
Groovy
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.1.0" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.tiles:tiles-material:1.1.0" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.1.0" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.1.0" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.1.0") // Use to utilize components and layouts with Material design in your tiles implementation("androidx.wear.tiles:tiles-material:1.1.0") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.1.0") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.1.0") }
创建卡片
如需在应用中提供卡片,请创建一个扩展 TileService
的类并实现方法,如以下代码示例所示:
Kotlin
private val RESOURCES_VERSION = "1" class MyTileService : TileService() { override fun onTileRequest(requestParams: RequestBuilders.TileRequest) = Futures.immediateFuture(Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTimeline(Timeline.Builder().addTimelineEntry( TimelineEntry.Builder().setLayout( Layout.Builder().setRoot( Text.Builder().setText("Hello world!").setFontStyle( FontStyle.Builder().setColor(argb(0xFF000000)).build() ).build() ).build() ).build() ).build() ).build()) override fun onResourcesRequest(requestParams: ResourcesRequest) = Futures.immediateFuture(Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ) }
Java
public class MyTileService extends TileService { private static final String RESOURCES_VERSION = "1"; @NonNull @Override protected ListenableFuture<Tile> onTileRequest( @NonNull TileRequest requestParams ) { return Futures.immediateFuture(new Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTimeline(new Timeline.Builder() .addTimelineEntry(new TimelineEntry.Builder() .setLayout(new Layout.Builder() .setRoot(new Text.Builder() .setText("Hello world!") .setFontStyle(new FontStyle.Builder() .setColor(argb(0xFF000000)).build() ).build() ).build() ).build() ).build() ).build() ); } @NonNull @Override protected ListenableFuture<Resources> onResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture(new Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ); } }
接下来,在 AndroidManifest.xml
文件的 <application>
标记内添加服务。
<service android:name=".MyTileService" android:label="@string/tile_label" android:description="@string/tile_description" android:exported="true" android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"> <intent-filter> <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" /> </intent-filter> <meta-data android:name="androidx.wear.tiles.PREVIEW" android:resource="@drawable/tile_preview" /> </service>
权限和 intent 过滤器会将此服务注册为卡片提供程序。
当用户在手机或手表上配置卡片时,系统会向用户显示图标、标签和说明。
借助预览元数据标记,当用户在手机上配置卡片时,可以显示卡片的预览。
为卡片创建界面
卡片的布局是使用构建器模式编写的。卡片布局的构建形式就像是一棵由布局容器和基本布局元素组成的树。每个布局元素都有其属性,您可以通过各种 setter 方法设置这些属性。
基本布局元素
支持以下视觉元素:
Material 组件
除了基本元素之外,tiles-material
库还提供了一些组件,用于确保卡片设计符合 Material Design 界面建议。
Button
:可点击的圆形组件,用于包含图标。Chip
:可点击的体育场形组件,最多可包含两行文本和一个可选图标。CompactChip
:可点击的体育场形组件,用于包含一行文本。TitleChip
:可点击的体育场形组件,与Chip
类似但高度更高,可容纳标题文本。CircularProgressIndicator
:可放在ProgressIndicatorLayout
内的圆形进度指示器,用于围绕屏幕边缘显示进度。
布局容器
支持以下容器:
Row
:一个接一个地水平排列子元素。Column
:一个接一个地垂直排列子元素。Box
:将一个子元素叠加在另一个子元素上。Arc
:沿着环形排列子元素。Spannable
:将特定的FontStyles
应用于文本的某些部分以及交错文本和图片。如需了解详情,请参阅 Spannable。
每个容器可以包含一个或多个子元素,这些子元素本身也可以是容器。例如,Column
可以包含多个 Row
元素作为子元素,从而形成类似于网格的布局。
作为参考,由一个容器布局和两个子布局元素组成的卡片可能如下所示:
Kotlin
private fun myLayout(): LayoutElement = Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VALIGN_BOTTOM) .addContent(Text.Builder() .setText("Hello world") .build() ) .addContent(Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build()
Java
private LayoutElement myLayout() { return new Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VALIGN_BOTTOM) .addContent(new Text.Builder() .setText("Hello world") .build() ) .addContent(new Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build(); }
Material 布局
除了基本布局之外,tiles-material
库还提供几种固定布局,用于将元素放到特定的“槽位”中。
PrimaryLayout
:将单个主要操作CompactChip
放在底部,内容居中置于其上。MultiSlotLayout
:放置主标签和次级标签,在两个标签之间放置可选内容,并在底部放置可选的CompactChip
。ProgressIndicatorLayout
:围绕着屏幕边缘放置CircularProgressIndicator
,内部放置指定内容。
弧形
支持以下 Arc
容器子元素:
ArcLine
:沿着弧形渲染一条曲线。ArcText
:沿着弧形渲染曲线文本。ArcAdapter
:沿着弧形渲染基本布局元素,在弧线的切线方向上进行绘制。
如需了解详情,请参阅每种元素类型的参考文档。
修饰符
对于每种可用的布局元素,您都可以选择对其应用修饰符。这些修饰符可用于以下用途:
- 更改布局的视觉外观。例如,为布局元素添加背景、边框或内边距。
- 添加有关布局的元数据。例如,为布局元素添加 semantics 修饰符,以便与屏幕阅读器结合使用。
- 添加功能。例如,为布局元素添加 clickable 修饰符,使用户可与卡片互动。如需了解详情,请参阅与卡片互动。
例如,我们可以自定义 Image
的默认外观和元数据,如以下代码示例所示:
Kotlin
private fun myImage(): LayoutElement = Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(Modifiers.Builder() .setBackground(Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(Padding.Builder().setStart(dp(12f)).build()) .setSemantics(Semantics.builder() .setContentDescription("Image description") .build() ).build() ).build()
Java
private LayoutElement myImage() { return new Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(new Modifiers.Builder() .setBackground(new Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(new Padding.Builder().setStart(dp(12f)).build()) .setSemantics(new Semantics.Builder() .setContentDescription("Image description") .build() ).build() ).build(); }
Spannable
Spannable
是一种特殊的容器,其元素布局方式与文本类似。如果您想仅针对一大段文本中的一个子字符串应用不同样式,使用 Text
元素是不可能实现的,此时 Spannable 就非常有用。
Spannable
容器中填充的是 Span
子元素。不允许填充其他子元素或嵌套的 Spannable
实例。
Span
子元素有两种类型:
例如,您可以将“Hello world”卡片中的“world”设为斜体,并在两个单词之间插入图片,如以下代码示例所示:
Kotlin
private fun mySpannable(): LayoutElement = Spannable.Builder() .addSpan(SpanText.Builder() .setText("Hello ") .build() ) .addSpan(SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(SpanText.Builder() .setText("world") .setFontStyle(FontStyle.Builder() .setItalic(true) .build()) .build() ).build()
Java
private LayoutElement mySpannable() { return new Spannable.Builder() .addSpan(new SpanText.Builder() .setText("Hello ") .build() ) .addSpan(new SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(new SpanText.Builder() .setText("world") .setFontStyle(newFontStyle.Builder() .setItalic(true) .build()) .build() ).build(); }
使用资源
卡片无法访问应用的任何资源。这意味着您无法将 Android 图片 ID 传递给 Image
布局元素并指望应用能够对其进行解析。请替换 onResourcesRequest()
方法并手动提供任何资源。
在 onResourcesRequest()
方法中,您可以通过以下两种方式提供图片:
- 使用
setAndroidResourceByResId()
提供可绘制资源。 - 使用
setInlineResource()
以ByteArray
形式提供动态图片。
Kotlin
override fun onResourcesRequest( requestParams: ResourcesRequest ) = Futures.immediateFuture( Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", ImageResource.Builder() .setAndroidResourceByResId(AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", ImageResource.Builder() .setInlineResource(InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() )
Java
@Override protected ListenableFuture<Resources> onResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture( new Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", new ImageResource.Builder() .setAndroidResourceByResId(new AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", new ImageResource.Builder() .setInlineResource(new InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() ); }