头图

Compose for Wear OS has released Developer Preview , and using Compose to build Wear OS apps not only makes it easy to follow the Material You guidelines, but at the same time brings out the benefits of Compose. Out of the box, it helps developers quickly build more beautiful Wear OS applications with less code. This article will help you better understand how to build with Compose by taking a look at the main composables in Wear Compose.

If you prefer to see this through video, please click here view it.

△ 主应用界面和通知界面

△ Main application interface and notification interface

Mobile applications often need to be developed for a variety of different interface types. Usually, the main interface that hosts the application consists of Fragment, Activity, and View. In the world of Compose, it consists of composable items. As a developer, you need to Understand and adapt to this change. On top of that, you're developing for an additional notification interface, which means you need to alert the user to some important information outside of the main app interface, or let them continue what they just did after launching the main app, Such as tracking running routes or playing music. If you use widgets, you can also use such an interface to provide information to users.

△ Wear OS 中不同的应用界面

△ Different application interfaces in Wear OS

OS has a variety of interfaces. When creating a complete OS application experience, you need to consider all of them:

  • Overlay Similar to the main interface of mobile applications, it used to consist of Activity, View and Fragment, but now it consists of composable items, which is very suitable for long or complex interactions;
  • The Notification interface also conforms to mobile application development guidelines;
  • Complication can provide information on the dial for direct viewing by users. Users only need to tap on the dial, and Complication can open the associated application, or perform independent operations, such as the drinking water record function, which records your water glass throughout the day. the frequency of drinking water;
  • Tile provides more space for displaying content, and users can swipe in any direction on the dial to quickly access information and perform operations.

In this article we'll focus on the Overlay interface and quickly demonstrate a few Wear composables to see how they work and how they are similar to mobile platforms.

add dependency

Before using Wear Compose, we need to make sure we have the correct dependencies, which is slightly different from Compose for mobile. On the mobile version, the main dependencies used are Material, Foundation, UI, Runtime and Compiler, and you can also choose to use Navigation and Animation dependencies. But in Wear, you can use the same UI dependencies, and the Runtime, Compiler, and Animation are all the same. Also, some other aspects are the same, such as the tooling and some Compose design philosophies, such as the use of bidirectional data flow.

But there are still some differences. For example, you need to use Wear Compose Material to replace Material. Technically speaking, the mobile version of Material can also be used directly, but it is not optimized for some features of Wear. We also recommend similar You use Wear Navigation instead of Navigation.

While we recommend using Wear Compose Material directly, you can still use Material Ripple, Material Icons Extended, etc. After adding the correct Wear dependencies, you're ready to start developing.

See dependency

Wear OS Material library introduction

Compose Wear OS Material library provides many of the same composables as on mobile platforms, you can replace Material theme , and customize colors, fonts, etc., except they are all optimized for watches. Next, we will introduce you to some commonly used composable items.

Button

Button is a compact interface element that the user can click to perform an action or make a selection.

Button can be easily added by the following code, although the style is different from the mobile version, the code is the same. We initialized a Button composable item in the code, and then declared some parameters, which are called Modifier. Many properties can be changed through Modifier, such as onClick, same, enabled here. If you want to add an icon to Button, Then you need to use the Icon composable that contains painter, contentDescription and modifier:

Button(
    modifier = Modifier.size (ButtonDefaults.LargeButtonSize),
    onClick = {... },
    enabled = enabledState
) {
    Icon(
        painter = painterResource (id = R.drawable.ic_phone),
        contentDescription = "phone",
        modifier = Modifier
            .size(24. dp)
            .wrapContentSize(align = Alignment.Center),
    )
}

△ Button combinable item code

Through the above code, we can create a beautiful and compact Button, the display effect is as follows:

△ Button 代码效果

△ Button code effect

Card

Card is flexible enough to present content and actions for a single topic.

The Card on the left side of the figure shows some icons and text, the middle interface only retains the text, and the right side uses an image as the background.

△ Card 用例

△ Card use case

In Wear OS, there are mainly AppCard and TitleCard. TitleCard focuses more on text display. In this article, we will focus on AppCard. The following sample code creates an AppCard and customizes the content through Image, Text and Column successively:

AppCard(
    appImage = {
        Image(painter = painterResource(id = R.drawable.ic_message), …)
    },
    appName = { Text ("Messages") },
    time = { Text ("12m" ) },
    title = { Text("Kim Green") },
    onClick = { … },
    body = {
        Column(modifier = Modifier.fillMaxWidth()) {
            Text("On my way!")
        }
    },
)

△ Card combinable item code

Through the above code, we have created a beautiful Card, the display effect is as follows:

△ Card 代码效果

△ Card code effect

To get a different look and feel for the beautiful card display, only minor adjustments to the code are required.

Chip

Chip is designed for quick, one-click operation, especially useful on Wear devices with limited screen space, and a variety of chip variants allow you to unleash your creativity.

Here's the code and implementation of the Chip composable, you'll find it very easy to use, and roughly similar to some of the code above:

Chip(
    modifier = Modifier.align(Alignment.CenterHorizontally),
    onClick = { … },
    enabled = enabledState,
    label = {
        Text(
            text = "1 minute Yoga",
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
    },
    icon = {
        Icon(
            painter = painterResource (id = R.drawable.ic_yoga),
            contentDescription= "yoga icon",
            modifier = Modifier
                .size(24.dp)
                .wrapContentSize(align = Alignment.Center),
        )
    },
)

△ Chip combinable item code

△ Chip 代码效果

△ Chip code effect

ToggleChip

ToggleChip is similar to Chip, the difference is that the user uses radio buttons, toggle switches, and checkboxes:

The ToggleChip use case is shown below:

△ ToggleChip 用例

△ ToggleChip use case

On the left of the picture, you can turn on and off the sound with just a tap; on the right of the picture, the ToggleChip is split, providing two different clickable areas, which can be turned off through the button on the right, and the application can be entered by clicking on the left Alarm clock for editing. Its code is similar:

ToggleChip(
    modifier = Modifier.height(32.dp)
    checked = checkedState,
    onCheckedChange = { … }
    label = {
        Text(
            text = "Sound",
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
    }
)

△ ToggleChip code

△ ToggleChip 代码效果

△ ToggleChip code effect

CurvedText and TimeText

CurvedText is specifically optimized for round screens, which is very important for round devices, and TimeText is a composable based on CurvedText, which handles all the text display work in terms of time for you.

The following code example shows how to create a TimeText and display it as a CurvedText:

var textBeforeTime by rememberSaveable { mutableStateOf("ETA 99 hours") }
// 首先创建在时间之前显示的前缀字符串
TimeText(  
// 创建 TimeText 可组合项
    leadingCurvedContent = {
        BasicCurvedText(
            text = textBeforeTime,
            style = TimeTextDefaults.timeCurvedTextStyle()
        )
    },
// 指定 leadingCurvedContent,在时间文本前显示文字,以 CurvedText 的方式在曲面设备上展示。
    leadingLinearContent = {
        Text(
            text = textBeforeTime,
            style = TimeTextDefaults.timeTextStyle()
        )
    },
// 指定 leadingLinearContent,在时间文本前显示文字,常规显示,适用于非曲面设备。
)

△ TimeText code

Through the above code, we can see that the display effect of the time text on the circular screen is as follows:

△ TimeText 显示效果

△ TimeText display effect

ScalingLazyColumn

A list is a component that is used in almost every application, and it displays a continuous interface element vertically. However, since the top and bottom space of the screen of Wear OS watch devices are very small, Material Design has introduced a new ScalingLazyColumn to display zoom and transparency, which helps you to view the content of the list in a smaller space.

△ ScalingLazyColumn display effect

The above picture shows the effect of ScalingLazyColumn. You can see that as the elements in the list slide in, when a row of the list is close to the center, it will be enlarged to the full size, and as the element slides out, it will become more and more It gets smaller (and becomes more transparent) until it disappears completely, which is great for the presentation of the content, which is easier for users to read.

The bottom layer of ScalingLazyColumn is implemented by LazyColumn. It will only process the content that is about to be presented on the screen, which can efficiently process large amounts of data and display it with zoom and transparency effects, so it should become the default component of Wear OS .

As above, the ScalingLazyColumn code example is as follows:

val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState()
 
ScalingLazyColumn(
    modifier = Modifier.fillMaxSize(),
    verticalArrangement = Arrangement.spacedBy(6.dp),
    state = scalingLazyListState,
) {
    items(messageList.size) { message ->
        Card(...) {...}
    }
    item {
        Card(...) {...}
    }
}

△ ScalingLazyColumn sample code

SwipeToDismissBox

This is the well-known Box component that is considered a container in the interface and can be used on mobile, but Wear has a dedicated version of SwipeToDismissBox that can be used in your layout, and as the name suggests, its function is to swipe to close. In Wear OS, the primary gesture is swiping, and swiping to the right using the SwipeToDismissBox is equivalent to hitting the "back" button.

val state = rememberSwipeToDismissBoxState()
 
SwipeToDismissBox(
    state = state,
){ isBackground ->
    if (isBackground) {
        Box(modifier = Modifier. fillMaxSize().background(MaterialTheme.colors.secondaryVariant))
    } else {
        Column(
            modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ){
            Text ("Swipe to dismiss", color = MaterialTheme.colors.onPrimary)
        }
    }
}

△ SwipeToDismissBox sample code

In the above code, we set the state property for SwipeToDismissBox, which is different from the mobile side. The isBackground callback value is obtained through the passed state, which represents whether the process is sliding back. You can display different content according to different states. The following picture is the final rendering effect:

△ SwipeToDismissBox 代码效果

△ SwipeToDismissBox code effect

So far, we have introduced some composable items of Wear OS. If you are familiar with the development of composable items on the mobile side, you may find that the development in Wear OS is basically the same. knowledge can be used directly in Wear OS development.

use Scaffold

Scaffold lets you implement an interface with a basic Material Design layout structure that provides slots for the most common top-level Material components such as TopBar, BottomBar, FloatingActionButton, and Drawer. When using Scaffold, you can ensure that these components are positioned correctly and work together. In Wear OS, it also has its own version. In addition to the same content components as the mobile version, it provides the following three main components:

△ Wear Scaffold 中的三个主要组件

△ The three main components in Wear Scaffold

  1. TimeText: You can place the time at the top of the screen, we have already introduced it, please refer to the section on TimeText above for details;
  2. Vignette: gives you a nice vignette effect around the screen, as shown in the image above;
  3. PositionIndicator: Also known as the scroll indicator, is an indicator on the right side of the screen that shows the current position of the indicator based on the type of state object you pass in. It's placed in the Scaffold because the screen is curved, so the position indicator needs to be in the center of the Scaffold, not just in the center of the viewport. Otherwise, the indicator may be truncated.

Scaffold Design

△ Scaffold 设计层级

△ Scaffold design level

When designing the Scaffold, please refer to the hierarchical order in the above figure for consideration. The first thing to do is to set the App, then set the MaterialTheme to customize the appearance and style of some applications, then consider how to place the Scaffold, and finally It is the definition of Content. This sequence is the same as on the mobile side. Consider setting up Theme first, then Scaffold, and then look at how to write the code:

// positionIndicator 在 Content 之外,因此要将 state 提升到 Scaffold 之上的级别
val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState()
 
MaterialTheme {
    Scaffold(
        modifier = Modifier.fillMaxSize(),
        timeText = {...},
        vignette = { 
            Vignette (vignettePosition = 
                VignettePosition.TopAndBottom)
        },
        positionIndicator = {
            // 通过查看 state 来判断是否处于滚动状态,若否,则不会进行展示
            if (scalingLazyListState.isScrollInProgress) {
                // PositionIndicator 需要用到 state,这也是我们从 LazyColumn 提升状态的主要原因
                PositionIndicator(scalingLazyListState =
                    scalingLazyListState)
            }
        }
    ) {
        // 设置 content
        …
    }
}

△ Scaffold sample code

In the above code, since the positionIndicator is outside the content, the state is raised to a level above the Scaffold to avoid it being truncated on the screen. While scrolling, you can check the scroll state, make more room for the screen by hiding the time display, and turn off or turn on the vignette effect based on the state. positionIndicator supports a variety of scrolling options. In this example, we use scalingLazyListState, and many other options with cool effects can be used. For details, please refer to the relevant documentation. There is no need to introduce too much about modifier and TimeText, and the setting of vignette is actually very simple.

Navigation

At the beginning of this article, it was mentioned that you need to use Wear Navigation dependency to replace Navigation, here again, you can still use Navigation technically, but you may encounter various problems, so it is recommended that you directly Use Wear Navigation optimized for Wear.

△ Navigation 设计

△ Navigation Design

The design of Navigation is roughly the same as that of Scaffold. It adopts the same design as the mobile version, except that SwipeDismissableNavHost is added under Scaffold and above Content. As the name suggests, this component supports slide-out operation. You can directly use the same design as mobile application development. knowledge to write code.

MaterialTheme {
    Scaffold(...){
        val navController = rememberSwipeDismissableNavController()
 
        SwipeDismissableNavHost(
            navController = navController,
            startDestination = Screen.MainScreen.route
        ) {
            composable(route = Screen.MainScreen.route){
                MyListScreen(...)
            }
            composable(route = Screen.DetailsScreen. route + "/{$ID}", ...) {
                MyDetailScreen(...)
            }
        }
    }
}

△ Navigation sample code

In the above code, the MaterialTheme and Scaffold are the same as before, but we create a navController and use the SwipeDismissable version of rememberSwipeDismissableNavController, which has a very hard name, but it's easy to understand what it does. Then use SwipeDismissableNavHost to pass the startDestination and its path to the controller, and then set the main screen content. You will find that the code is basically the same as on the mobile side, which is very easy to understand.

Summary

In Wear OS, make sure to use the appropriate dependencies, replace Material and add the Foundation dependencies, if you're using Navigation as well. In addition, all the knowledge of Compose building can be directly applied to Wear Compose, and the mobile terminal development experience can help you quickly build beautiful Wear interface.

For more details, see:

You are welcome Click here to submit feedback to us, or share your favorite content and problems found. Your feedback is very important to us, thank you for your support!


Android开发者
404 声望2k 粉丝

Android 最新开发技术更新,包括 Kotlin、Android Studio、Jetpack 和 Android 最新系统技术特性分享。更多内容,请关注 官方 Android 开发者文档。