Compose for Wear: CurvedRow() and CurvedText()

Compose UI is not just for phones, tablets, foldables, notebooks, and desktops.Compose UI is for watches as well, via the Compose for Wear set of libraries.

(Google calls it ���Wear Compose��� on that page, but that just makes me think���Wear Compose? There! There Compose!���).

(and, yes, I���m old)

Compose for Wear has a bunch of composables designed for the watch experience.In particular, Compose for Wear has support for having content curve to matchthe edges of a round Wear OS device.

The Compose for Wear edition of Scaffold() has a timeText parameter. Thisis a slot API, taking a composable as a value, where typically you will see thatcomposable delegate purely to TimeText(). That gives you the current timeacross the top of the watch screen, including curving that time on round screens:

[image error]

The implementation of TimeText() uses CurvedRow() and CurvedText() to accomplish this,if the code is running on a round device. Otherwise, it uses the normal Row() andText() composables,

TimeText() is a bit overblown, particularly for a blog post, sothis sample projecthas a SimpleTimeText() composable with a subset of the functionality:

@ExperimentalWearMaterialApi@Composablefun SimpleTimeText( modifier: Modifier = Modifier, timeSource: TimeSource = TimeTextDefaults.timeSource(TimeTextDefaults.timeFormat()), timeTextStyle: TextStyle = TimeTextDefaults.timeTextStyle(), contentPadding: PaddingValues = PaddingValues(4.dp)) { val timeText = timeSource.currentTime if (LocalConfiguration.current.isScreenRound) { CurvedRow(modifier.padding(contentPadding)) { CurvedText( text = timeText, style = CurvedTextStyle(timeTextStyle) ) } } else { Row( modifier = modifier .fillMaxSize() .padding(contentPadding), verticalAlignment = Alignment.Top, horizontalArrangement = Arrangement.Center ) { Text( text = timeText, style = timeTextStyle, ) } }}

We can determine whether or not the screen is round from the isScreenRoundproperty on the Configuration, which we get via LocalConfiguration.current.If the screen is round, we display the current time in a CurvedText() and wrapthat in a CurvedRow(). CurvedText() knows how to have the letters of the textfollow the curve of the screen, and CurvedRow() knows how to have child composablesfollow the curve of the screen.

The timeText slot parameter in Scaffold() puts the time at the top of thescreen by default. That position is controlled by the anchor parameter toCurvedRow(), where the default anchor is 270f. anchor is measured in degrees,and 270f is the value for the top of the screen (probably for historical reasons).

SampleRow() in that sample project lets us display multiple separate stringsvia individual CurvedText() composables, in a CurvedRow() with a custom anchor value:

@Composableprivate fun SampleRow(anchor: Float, modifier: Modifier, vararg textBits: String) { CurvedRow( modifier = modifier.padding(4.dp), anchor = anchor ) { textBits.forEach { CurvedText(it, modifier = Modifier.padding(end = 8.dp)) } }}

SampleRow() accepts a Modifier and tailors it to add a bit of padding to the CurvedRow().

We can then use SampleRow() to display text in other positions on the screen:

@ExperimentalWearMaterialApi@Composablefun MainScreen() { Scaffold( timeText = { SimpleTimeText() }, content = { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text(text = "Hello, world!") SampleRow(anchor = 180f, modifier = Modifier.align(Alignment.CenterStart), "one", "two", "three") SampleRow(anchor = 0f, modifier = Modifier.align(Alignment.CenterEnd), "uno", "dos", "tres") SampleRow(anchor = 90f, modifier = Modifier.align(Alignment.BottomCenter), "eins", "zwei", "drei") } } )}

An anchor of 0f is the end edge of the screen, 90f is the bottom, and 180f is the start edge.Note that we also use align() to control the positioning within the Box(), with valuesthat line up with our chosen anchor values.

The result is that we have text on all four edges, plus a centered ���Hello, world!���:

[image error]

CurvedRow() does not handle consecutive bits of CurvedText() all that well ���ideally, use a single CurvedText() with the combined text. However, CurvedRow()is not limited to CurvedText(), and I hope to explore that more in a future blog post.

 •  0 comments  •  flag
Share on Twitter
Published on January 17, 2022 06:43
No comments have been added yet.