はじめに
xmlを用いたWatch Faceの作成方法について紹介。
Android StudioのNew Project→Watch Faceでのプロジェクト作成だと、非推奨クラス(CanvasWatchFaceService
)を使用することになるので1から作成した(2022/09/27時点)。

作成方法
依存関係の宣言
build.gradle(:app)
ファイルにWatchFace用の依存関係を追加
build.gradle
dependencies {
implementation 'androidx.wear.watchface:watchface:1.1.1'
}
レイアウトの作成
WatchFaceに表示するレイアウトの作成
custom_watch_face.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#FF000000"
android:layout_height="match_parent">
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="52sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12:34"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Rendererクラスの作成
XMLのレイアウトを描画する処理を記述
CustomWatchFaceRenderer.kt
class CustomWatchFaceRenderer(
context: Context,
surfaceHolder: SurfaceHolder,
currentUserStyleRepository: CurrentUserStyleRepository,
watchState: WatchState
) : Renderer.CanvasRenderer2<Renderer.SharedAssets>(
surfaceHolder,
currentUserStyleRepository,
watchState,
CanvasType.HARDWARE,
16L,
false
) {
private val binding = CustomWatchFaceBinding.inflate(LayoutInflater.from(context))
override suspend fun createSharedAssets() = object : SharedAssets {
override fun onDestroy() {}
}
override fun renderHighlightLayer(canvas: Canvas, bounds: Rect, zonedDateTime: ZonedDateTime, sharedAssets: SharedAssets) {}
override fun render(canvas: Canvas, bounds: Rect, zonedDateTime: ZonedDateTime, sharedAssets: SharedAssets) {
if (renderParameters.watchFaceLayers.contains(WatchFaceLayer.COMPLICATIONS_OVERLAY)) {
binding.root.measure(
View.MeasureSpec.makeMeasureSpec(bounds.width(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(bounds.height(), View.MeasureSpec.EXACTLY)
)
binding.root.layout(0, 0, bounds.width(), bounds.height())
binding.time.text = String.format("%02d:%02d", zonedDateTime.hour, zonedDateTime.minute)
binding.root.draw(canvas)
}
}
}
WatchFaceServiceの作成
先ほど作成したRendererクラスを使ってWatchFaceServiceを作成
CustomWatchFaceService.kt
class CustomWatchFaceService : WatchFaceService() {
override suspend fun createWatchFace(surfaceHolder: SurfaceHolder, watchState: WatchState, complicationSlotsManager: ComplicationSlotsManager, currentUserStyleRepository: CurrentUserStyleRepository) =
WatchFace(WatchFaceType.DIGITAL, CustomWatchFaceRenderer(applicationContext, surfaceHolder, currentUserStyleRepository, watchState))
}
Wallpaperの作成
res/xml/watch_face.xml
の作成
watch_face.xml
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper/>
プレビュー画像の配置
res/drawable/preview.png
を配置
マニフェストファイルの変更
WatchFace一覧に先ほど作成したWatchFaceを表示させる。
パーミッションにWAKE_LOCK
を追加
WatchFaceServiceにCustomWatchFaceService
を指定
AndroidManifest.xml
<manifest ...>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
...
<application ...>
...
<service
android:name=".CustomWatchFaceService"
android:label="Custom Watch Face"
android:permission="android.permission.BIND_WALLPAPER"
android:exported="true">
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/watch_face"/>
<meta-data
android:name="com.google.android.wearable.watchface.preview"
android:resource="@drawable/preview"/>
<meta-data
android:name="com.google.android.wearable.watchface.preview_circular"
android:resource="@drawable/preview"/>
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService"/>
<category android:name="com.google.android.wearable.watchface.category.WATCH_FACE"/>
</intent-filter>
</service>
</application>
</manifest>
参考サイト
処理関連:
依存関係関連:
サンプルコード: