Skip to content

Commit cafc3dd

Browse files
Snippets for some Wear OS Tile pages (#554)
1 parent 81b5d86 commit cafc3dd

File tree

2 files changed

+460
-3
lines changed

2 files changed

+460
-3
lines changed
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.wear.snippets.tile
18+
19+
import android.annotation.SuppressLint
20+
import androidx.annotation.OptIn
21+
import androidx.wear.protolayout.DeviceParametersBuilders
22+
import androidx.wear.protolayout.DimensionBuilders.degrees
23+
import androidx.wear.protolayout.DimensionBuilders.dp
24+
import androidx.wear.protolayout.LayoutElementBuilders
25+
import androidx.wear.protolayout.LayoutElementBuilders.Arc
26+
import androidx.wear.protolayout.LayoutElementBuilders.ArcLine
27+
import androidx.wear.protolayout.ModifiersBuilders
28+
import androidx.wear.protolayout.ModifiersBuilders.AnimatedVisibility
29+
import androidx.wear.protolayout.ModifiersBuilders.DefaultContentTransitions
30+
import androidx.wear.protolayout.ModifiersBuilders.Modifiers
31+
import androidx.wear.protolayout.TimelineBuilders.Timeline
32+
import androidx.wear.protolayout.TypeBuilders.FloatProp
33+
import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters
34+
import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec
35+
import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat
36+
import androidx.wear.protolayout.expression.ProtoLayoutExperimental
37+
import androidx.wear.protolayout.material.CircularProgressIndicator
38+
import androidx.wear.protolayout.material.Text
39+
import androidx.wear.protolayout.material.layouts.EdgeContentLayout
40+
import androidx.wear.tiles.RequestBuilders
41+
import androidx.wear.tiles.TileBuilders.Tile
42+
import androidx.wear.tiles.TileService
43+
import com.google.common.util.concurrent.Futures
44+
import com.google.common.util.concurrent.ListenableFuture
45+
46+
private const val RESOURCES_VERSION = "1"
47+
private const val someTileText = "Hello"
48+
private val deviceParameters = DeviceParametersBuilders.DeviceParameters.Builder().build()
49+
50+
private fun getTileTextToShow(): String {
51+
return "Some text"
52+
}
53+
54+
/** Demonstrates a sweep transition animation on a [CircularProgressIndicator]. */
55+
class AnimationSweepTransition : TileService() {
56+
// [START android_wear_tile_animations_sweep_transition]
57+
private var startValue = 15f
58+
private var endValue = 105f
59+
private val animationDurationInMillis = 2000L // 2 seconds
60+
61+
override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture<Tile> {
62+
val circularProgressIndicator =
63+
CircularProgressIndicator.Builder()
64+
.setProgress(
65+
FloatProp.Builder(/* static value */ 0.25f)
66+
.setDynamicValue(
67+
// Or you can use some other dynamic object, for example
68+
// from the platform and then at the end of expression
69+
// add animate().
70+
DynamicFloat.animate(
71+
startValue,
72+
endValue,
73+
AnimationSpec.Builder()
74+
.setAnimationParameters(
75+
AnimationParameters.Builder()
76+
.setDurationMillis(animationDurationInMillis)
77+
.build()
78+
)
79+
.build(),
80+
)
81+
)
82+
.build()
83+
)
84+
.build()
85+
86+
return Futures.immediateFuture(
87+
Tile.Builder()
88+
.setResourcesVersion(RESOURCES_VERSION)
89+
.setTileTimeline(Timeline.fromLayoutElement(circularProgressIndicator))
90+
.build()
91+
)
92+
}
93+
// [END android_wear_tile_animations_sweep_transition]
94+
}
95+
96+
/** Demonstrates setting the growth direction of an [Arc] and [ArcLine]. */
97+
@SuppressLint("RestrictedApi")
98+
class AnimationArcDirection : TileService() {
99+
// [START android_wear_tile_animations_set_arc_direction]
100+
public override fun onTileRequest(
101+
requestParams: RequestBuilders.TileRequest
102+
): ListenableFuture<Tile> {
103+
return Futures.immediateFuture(
104+
Tile.Builder()
105+
.setResourcesVersion(RESOURCES_VERSION)
106+
.setTileTimeline(
107+
Timeline.fromLayoutElement(
108+
EdgeContentLayout.Builder(deviceParameters)
109+
.setResponsiveContentInsetEnabled(true)
110+
.setEdgeContent(
111+
Arc.Builder()
112+
// Arc should always grow clockwise.
113+
.setArcDirection(LayoutElementBuilders.ARC_DIRECTION_CLOCKWISE)
114+
.addContent(
115+
ArcLine.Builder()
116+
// Set color, length, thickness, and more.
117+
// Arc should always grow clockwise.
118+
.setArcDirection(
119+
LayoutElementBuilders.ARC_DIRECTION_CLOCKWISE
120+
)
121+
.build()
122+
)
123+
.build()
124+
)
125+
.build()
126+
)
127+
)
128+
.build()
129+
)
130+
}
131+
// [END android_wear_tile_animations_set_arc_direction]
132+
}
133+
134+
/** Demonstrates smooth fade-in and fade-out transitions. */
135+
class AnimationFadeTransition : TileService() {
136+
137+
@OptIn(ProtoLayoutExperimental::class)
138+
// [START android_wear_tile_animations_fade]
139+
public override fun onTileRequest(
140+
requestParams: RequestBuilders.TileRequest
141+
): ListenableFuture<Tile> {
142+
// Assumes that you've defined a custom helper method called
143+
// getTileTextToShow().
144+
val tileText = getTileTextToShow()
145+
return Futures.immediateFuture(
146+
Tile.Builder()
147+
.setResourcesVersion(RESOURCES_VERSION)
148+
.setTileTimeline(
149+
Timeline.fromLayoutElement(
150+
Text.Builder(this, tileText)
151+
.setModifiers(
152+
Modifiers.Builder()
153+
.setContentUpdateAnimation(
154+
AnimatedVisibility.Builder()
155+
.setEnterTransition(DefaultContentTransitions.fadeIn())
156+
.setExitTransition(DefaultContentTransitions.fadeOut())
157+
.build()
158+
)
159+
.build()
160+
)
161+
.build()
162+
)
163+
)
164+
.build()
165+
)
166+
}
167+
// [END android_wear_tile_animations_fade]
168+
}
169+
170+
/** Demonstrates smooth slide-in and slide-out transitions. */
171+
class AnimationSlideTransition : TileService() {
172+
@OptIn(ProtoLayoutExperimental::class)
173+
// [START android_wear_tile_animations_slide]
174+
public override fun onTileRequest(
175+
requestParams: RequestBuilders.TileRequest
176+
): ListenableFuture<Tile> {
177+
// Assumes that you've defined a custom helper method called
178+
// getTileTextToShow().
179+
val tileText = getTileTextToShow()
180+
return Futures.immediateFuture(
181+
Tile.Builder()
182+
.setResourcesVersion(RESOURCES_VERSION)
183+
.setTileTimeline(
184+
Timeline.fromLayoutElement(
185+
Text.Builder(this, tileText)
186+
.setModifiers(
187+
Modifiers.Builder()
188+
.setContentUpdateAnimation(
189+
AnimatedVisibility.Builder()
190+
.setEnterTransition(
191+
DefaultContentTransitions.slideIn(
192+
ModifiersBuilders.SLIDE_DIRECTION_LEFT_TO_RIGHT
193+
)
194+
)
195+
.setExitTransition(
196+
DefaultContentTransitions.slideOut(
197+
ModifiersBuilders.SLIDE_DIRECTION_LEFT_TO_RIGHT
198+
)
199+
)
200+
.build()
201+
)
202+
.build()
203+
)
204+
.build()
205+
)
206+
)
207+
.build()
208+
)
209+
}
210+
// [END android_wear_tile_animations_slide]
211+
}
212+
213+
/** Demonstrates a rotation transformation. */
214+
class AnimationRotation : TileService() {
215+
override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture<Tile> {
216+
// [START android_wear_tile_animations_rotation]
217+
return Futures.immediateFuture(
218+
Tile.Builder()
219+
.setResourcesVersion(RESOURCES_VERSION)
220+
.setTileTimeline(
221+
Timeline.fromLayoutElement(
222+
Text.Builder(this, someTileText)
223+
.setModifiers(
224+
Modifiers.Builder()
225+
.setTransformation(
226+
ModifiersBuilders.Transformation.Builder()
227+
// Set the pivot point 50 dp from the left edge
228+
// and 100 dp from the top edge of the screen.
229+
.setPivotX(dp(50f))
230+
.setPivotY(dp(100f))
231+
// Rotate the element 45 degrees clockwise.
232+
.setRotation(degrees(45f))
233+
.build()
234+
)
235+
.build()
236+
)
237+
.build()
238+
)
239+
)
240+
.build()
241+
)
242+
// [END android_wear_tile_animations_rotation]
243+
}
244+
}
245+
246+
/** Demonstrates a scaling transformation. */
247+
class AnimationScaling : TileService() {
248+
override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture<Tile> {
249+
// [START android_wear_tile_animations_scaling]
250+
return Futures.immediateFuture(
251+
Tile.Builder()
252+
.setResourcesVersion(RESOURCES_VERSION)
253+
.setTileTimeline(
254+
Timeline.fromLayoutElement(
255+
Text.Builder(this, someTileText)
256+
.setModifiers(
257+
Modifiers.Builder()
258+
.setTransformation(
259+
ModifiersBuilders.Transformation.Builder()
260+
// Set the pivot point 50 dp from the left edge
261+
// and 100 dp from the top edge of the screen.
262+
.setPivotX(dp(50f))
263+
.setPivotY(dp(100f))
264+
// Shrink the element by a scale factor
265+
// of 0.5 horizontally and 0.75 vertically.
266+
.setScaleX(FloatProp.Builder(0.5f).build())
267+
.setScaleY(
268+
FloatProp.Builder(0.75f).build()
269+
)
270+
.build()
271+
)
272+
.build()
273+
)
274+
.build()
275+
)
276+
)
277+
.build()
278+
)
279+
// [END android_wear_tile_animations_scaling]
280+
}
281+
}
282+
283+
/** Demonstrates a geometric translation. */
284+
class AnimationGeometricTranslation : TileService() {
285+
override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture<Tile> {
286+
// [START android_wear_tile_animations_geometric_translation]
287+
return Futures.immediateFuture(
288+
Tile.Builder()
289+
.setResourcesVersion(RESOURCES_VERSION)
290+
.setTileTimeline(
291+
Timeline.fromLayoutElement(
292+
Text.Builder(this, someTileText)
293+
.setModifiers(
294+
Modifiers.Builder()
295+
.setTransformation(
296+
ModifiersBuilders.Transformation.Builder()
297+
// Translate (move) the element 60 dp to the right
298+
// and 80 dp down.
299+
.setTranslationX(dp(60f))
300+
.setTranslationY(dp(80f))
301+
.build()
302+
)
303+
.build()
304+
)
305+
.build()
306+
)
307+
)
308+
.build()
309+
)
310+
// [END android_wear_tile_animations_geometric_translation]
311+
}
312+
}

0 commit comments

Comments
 (0)