Android NDK开发详解Wear之功能块使用入门
如需开始在应用中提供功能块,请在应用的 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")
}
注意:此 API 是异步的,并且广泛依赖于 ListenableFuture。如需详细了解此概念,请参阅使用 ListenableFuture。
创建功能块
如需在应用中提供功能块,请创建一个扩展 TileService 的类并实现相应方法,如以下代码示例所示:
Kotlin
// Uses the ProtoLayout namespace for tile timeline objects.
// If you haven't done so already, migrate to the ProtoLayout namespace.
import androidx.wear.protolayout.TimelineBuilders.Timeline
import androidx.wear.protolayout.material.Text
import androidx.wear.tiles.TileBuilders.Tile
private val RESOURCES_VERSION = "1"
class MyTileService : TileService() {
override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
Futures.immediateFuture(Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(
Timeline.fromLayoutElement(
Text.Builder(this, "Hello world!")
.setTypography(Typography.TYPOGRAPHY_DISPLAY1)
.setColor(argb(0xFF000000.toInt()))
.build()))
.build())
override fun onTileResourcesRequest(requestParams: ResourcesRequest) =
Futures.immediateFuture(Resources.Builder()
.setVersion(RESOURCES_VERSION)
.build()
)
}
Java
// Uses the ProtoLayout namespace for tile timeline objects.
// If you haven't done so already, migrate to the ProtoLayout namespace.
import androidx.wear.protolayout.TimelineBuilders.Timeline;
import androidx.wear.protolayout.material.Text;
import androidx.wear.tiles.TileBuilders.Tile;
public class MyTileService extends TileService {
private static final String RESOURCES_VERSION = "1";
protected ListenableFuture<Tile> onTileRequest(
TileRequest requestParams
) {
return Futures.immediateFuture(new Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(
Timeline.fromLayoutElement(
new Text.Builder(this, "Hello world!")
.setTypography(Typography.TYPOGRAPHY_DISPLAY1)
.setColor(ColorBuilders.argb(0xFF000000))
.build()))
.build()
);
}
protected ListenableFuture<Resources> onTileResourcesRequest(
ResourcesRequest requestParams
) {
return Futures.immediateFuture(new Resources.Builder()
.setVersion(RESOURCES_VERSION)
.build()
);
}
}
接下来,在 AndroidManifest.xml 文件的 标记内添加服务。
<service
android:name=".MyTileService"
android:label="@string/tile_label"
android:description="@string/tile_description"
android:icon="@drawable/tile_icon_round"
android:roundIcon="@drawable/tile_icon_round"
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 方法设置这些属性。
注意:可以在布局中显示的嵌套元素的数量是有限的。如果超出相应限制,系统会忽略布局更新,并显示功能块之前的状态。
基本布局元素
支持 protolayout 库中的以下视觉元素以及 Material 组件:
Text:渲染文本字符串,可选择是否换行。
Image:渲染图片。
Spacer:设置元素之间的内边距,也可在设置背景颜色时用作分隔线。
Material 组件
除了基本元素之外,protolayout-material 库还提供了一些组件,用于确保功能块设计符合 Material Design 界面建议。
Button:可点击的圆形组件,用于包含图标。
Chip:可点击的体育场形组件,最多可包含两行文本和一个可选图标。
注意:如果您在 Column 元素内使用 Chip 元素,请将这两个元素的宽度均设置为 expand()。
CompactChip:可点击的体育场形组件,用于包含一行文本。
TitleChip:可点击的体育场形组件,与 Chip 类似但高度更高,可容纳标题文本。
CircularProgressIndicator:可放在 EdgeContentLayout 内的圆形进度指示器,用于围绕屏幕边缘显示进度。
布局容器
支持以下容器以及 Material 布局:
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 布局
除了基本布局之外,protolayout-material 库还提供了几种固定布局,用于将元素放到特定的“槽位”中。
PrimaryLayout:将单个主要操作 CompactChip 放在底部,内容居中置于其上。
注意:使用此布局时,您不能调用 expand() 来设置内容的高度。否则,您可能会看到空白功能块。
不过,您可以对内容的宽度调用 expand(),以使用父元素外边距之间的所有空间。
MultiSlotLayout:放置主标签和次级标签,在两个标签之间放置可选内容,并在底部放置可选的 CompactChip。
MultiButtonLayout:放置一组根据 Material 准则排列的按钮。
EdgeContentLayout:将内容沿着屏幕边缘放置,例如 CircularProgressIndicator。使用此布局时,系统会自动为其中的内容应用适当的外边距和内边距。
弧形
支持以下 Arc 容器子元素:
ArcLine:沿着弧形渲染一条曲线。
ArcText:沿着弧形渲染曲线文本。
ArcAdapter:沿着弧形渲染基本布局元素,在弧线的切线方向上进行绘制。
注意:使用 ArcText 会沿着弧形绘制曲线文本,而在 ArcAdapter 中使用 Text 则会沿着弧线的切线绘制直线文本。
如需了解详情,请参阅每种元素类型的参考文档。
修饰符
对于每种可用的布局元素,您都可以选择对其应用修饰符。这些修饰符有以下用途:
更改布局的视觉外观。例如,为布局元素添加背景、边框或内边距。
添加有关布局的元数据。例如,为布局元素添加 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 子元素有两种类型:
SpanText:渲染特定样式的文本。
SpanImage:渲染内嵌文本的图片。
例如,您可以将“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 布局元素并指望应用能够对其进行解析。您需要替换 onTileResourcesRequest() 方法并手动提供所有资源。
在 onTileResourcesRequest() 方法中,您可以通过以下两种方式提供图片:
使用 setAndroidResourceByResId() 提供可绘制资源。
使用 setInlineResource() 以 ByteArray 形式提供动态图片。
Kotlin
override fun onTileResourcesRequest(
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
ListenableFuture<Resources> onTileResourcesRequest(
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()
);
}
protected
目前没有任何推荐文档页面。
请尝试登录您的 Google 账号。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2023-11-20。