適用于 Wear OS 的 Compose 已推出了開發者預覽版,使用 Compose 構建 Wear OS 應用,不僅可以輕松遵循 Material You 指南,同時可以將 Compose 的優點發揮出來。開箱即用,幫助開發者使用更少的代碼快速構建出更精美的 Wear OS 應用。本文將通過 Wear Compose 主要的可組合項 (Composable) 來幫助您更好地了解如何使用 Compose 來進行構建。
移動應用往往需要針對多種不同的界面種類進行開發,通常情況下,承載應用的主界面由 Fragment、Activity 和 View 構成,而在 Compose 的世界中則是由可組合項構成,作為開發者您需要了解并適應這種變化。除此之外,您還要針對額外的通知界面進行開發,這意味著您需要在主應用界面之外提醒用戶注意某些重要信息,或讓他們在啟動主應用后繼續完成剛剛執行的操作,例如跟蹤跑步路線或者播放音樂。如果您使用了 Widget,也可以借助此類界面向用戶提供信息。
Wear OS 擁有多種界面,在打造完備的 Wear OS 應用體驗時,需要您全部考慮:
疊加層 (Overlay) 與移動應用的主界面類似,之前由 Activity、View 和 Fragment 組成,現在由可組合項構成,非常適合流程較長或較為復雜的交互;
通知 (Notification) 界面同樣符合移動應用開發準則;
復雜功能 (Complication) 可在表盤中提供信息便于用戶直接查看,用戶只需在表盤上輕點一下,Complication 即可打開相關聯的應用,或執行獨立操作,例如飲水記錄功能,記錄您一天用水杯喝水的次數;
圖塊 (Tile) 提供了更多展示內容的空間,用戶可在表盤上通過任意方向滑動,快速訪問信息、執行操作。
多種界面
https://developer.android.google.cn/training/wearables/user-interfaces
疊加層 (Overlay)
https://developer.android.google.cn/training/wearables/overlays
本文我們將著重介紹 Overlay 界面,并快速演示幾項 Wear 可組合項,了解它們的工作原理及其與移動平臺的相似之處。
添加依賴項
在使用 Wear Compose 之前,我們需要先確保已有正確的依賴項,它同移動版 Compose 略有不同。在移動版上,主要使用的依賴項有 Material、Foundation、UI、Runtime 和 Compiler,您還可以選擇使用 Navigation 和 Animation 依賴。但在 Wear 中,您可以使用一樣的 UI 依賴項,Runtime、Compiler 和 Animation 也都是相同的。此外,其他一些方面也都是相同的,比如工具和一些 Compose 設計理念,比如使用雙向數據流。
但還是有一些不同之處的,比如您需要使用 Wear Compose Material 替換 Material,單從技術上來說移動版 Material 也是可以直接用的,但它并沒有針對 Wear 的一些特性進行優化,類似的我們還推薦您使用 Wear Navigation 來替換 Navigation。
雖然我們建議直接使用 Wear Compose Material,但您仍然可以使用 Material Ripple 和 Material Icons Extended 等。在添加正確的 Wear 依賴項后,您就可以著手進行開發了。
在 Wear Compose 文檔頁面查看依賴項: https://developer.android.google.cn/jetpack/androidx/releases/wear-compose#declaring_dependencies
Wear OS Material 庫介紹
Compose Wear OS Material 庫提供了很多與移動平臺上相同的可組合項,您可以替換 Material 主題,并且自定義顏色、字體等,不同的是它們都針對手表進行了優化。接下來我們就為您介紹一些常用的可組合項。
Compose Wear OS Material 庫
https://developer.android.google.cn/reference/kotlin/androidx/wear/compose/material/package-summary.html
Material 主題
https://developer.android.google.cn/training/wearables/components/theme
Button
Button 屬于緊湊的界面元素,用戶可通過點按 Button 執行操作或做出選擇。 https://developer.android.google.cn/training/wearables/components/buttons 通過如下代碼可輕松添加 Button,雖然樣式與移動版不同,但代碼一樣。我們在代碼里初始化了一個 Button 可組合項,然后聲明了一些參數,它們被稱為 Modifier,通過 Modifier 可以更改很多屬性,比如這里的 onClick、same、enabled,若您還想為 Button 添加一個圖標,那就需要用到包含 painter、contentDescription 和 modifier 的 Icon 可組合項:
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 可組合項代碼
通過上述代碼,我們可以創建精美小巧的 Button,顯示效果如下:
△Button 代碼效果
Card
Card 可針對單一主題的內容和操作進行呈現,十分靈活。
https://developer.android.google.cn/training/wearables/components/cards
如圖左側 Card 展示了一些圖標和文字,中間界面只保留了文字,右側使用了一張圖片作為背景。
△Card 用例
在 Wear OS 中,主要有 AppCard 和 TitleCard 兩種 Card,TitleCard 更側重文字展示,本文我們將著重介紹 AppCard。如下示例代碼創建了一個 AppCard,并相繼通過 Image、Text 和 Column 定制內容:
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 可組合項代碼 通過上述代碼,我們創建出了一個精美的 Card,顯示效果如下:
△Card代碼效果
如需獲得不同外觀的精美卡片顯示效果,僅需對代碼進行輕微調整即可。 Chip Chip 旨在實現快捷的一鍵操作,對屏幕空間有限的 Wear 設備尤其有用,各種 Chip 變體也能讓您盡情揮灑創意: https://developer.android.google.cn/training/wearables/components/chips 下面是實現 Chip 可組合項的代碼和實現效果,您會發現它十分易用,同上述的一些代碼也大致相似:
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可組合項代碼
△Chip 代碼效果
ToggleChip ToggleChip 和 Chip 類似,區別是用戶使用單選按鈕、切換開關、復選框: https://developer.android.google.cn/training/wearables/components/toggle-chips 如下所示 ToggleChip 用例:
△ToggleChip 用例
圖左展示,只需輕點即可開關聲音;圖右則對 ToggleChip 進行了拆分,提供了兩個不同的可點擊區域,通過右側按鈕可將其關閉,點擊左側可以進入應用以便對鬧鐘進行編輯。其代碼大同小異:
ToggleChip( modifier = Modifier.height(32.dp) checked = checkedState, onCheckedChange = { … } label = { Text( text = "Sound", maxLines = 1, overflow = TextOverflow.Ellipsis ) })
△ToggleChip 代碼
△?ToggleChip 代碼效果
CurvedText 和 TimeText CurvedText 專門針對了圓形屏幕進行了優化,這對圓形設備來說非常重要,而 TimeText 是基于 CurvedText 所創建的可組合項,它為您處理時間方面的所有文字顯示工作。
https://developer.android.google.cn/training/wearables/components/curved-text
如下代碼示例展示了如何創建 TimeText,并以 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 代碼
通過上述代碼,我們可以看到時間文本在圓形屏幕的顯示效果如下:
△TimeText 顯示效果 ScalingLazyColumn 列表幾乎是每個應用中都會用到的組件,它縱向展示了連續的界面元素。但由于 Wear OS 手表設備的屏幕頂部和底部空間都非常小,因此 Material Design 引入了新的 ScalingLazyColumn 來進行縮放和透明度的展示,這樣有助于您在較小的空間內查看列表的內容。 △ScalingLazyColumn顯示效果 上圖展示了 ScalingLazyColumn 的效果,您可以看到隨著列表內元素的滑入,當列表的某一行靠近中心位置時,會放大到完整尺寸,而隨著該元素的滑出,會變得越來越小 (并且變得更透明) 直至完全消失,這種效果十分有利于內容的展示,內容更易于用戶閱讀。 ScalingLazyColumn 底層是由 LazyColumn 實現的,它只會對即將要在屏幕上呈現的內容進行處理,這樣能夠高效地處理大量數據,且能夠以縮放和透明效果進行展示,因此它應該成為 Wear OS 的默認組件。 如上效果,ScalingLazyColumn 代碼示例如下:
val scalingLazyListState: ScalingLazyListState = rememberScalingLazyListState() ScalingLazyColumn( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(6.dp), state = scalingLazyListState,) { items(messageList.size) { message -> Card(...) {...} } item { Card(...) {...} }}
△ScalingLazyColumn 示例代碼
SwipeToDismissBox
這是大家十分熟悉的 Box 組件被視為界面中的一個容器,可在移動端使用,但 Wear 中有專屬版本 SwipeToDismissBox,可用于您的布局,顧名思義它的功能是滑動以關閉。在 Wear OS 中,主要的手勢就是滑動,通過使用 SwipeToDismissBox 向右滑動,就相當于點擊了 "返回"按鈕。
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 示例代碼
在上述代碼中,我們為 SwipeToDismissBox 設置了 state 屬性,這一點和移動端不同。通過傳遞的 state 獲取到 isBackground 回調值,它代表了此過程是否是滑動返回,您可以根據不同的狀態展示不同的內容。下圖是最終的呈現效果:
△SwipeToDismissBox 代碼效果
至此,我們介紹了一些 Wear OS 的可組合項,若您對移動端的可組合項開發有所了解,您可能會發現在 Wear OS 中開發基本是一樣的,換句話說,您之前學習 Compose 時掌握的知識可以直接用于 Wear OS 開發。
使用 Scaffold
Scaffold 可讓您實現具有基本 Material Design 布局結構的界面,它可為最常見的頂層 Material 組件 (例如 TopBar、BottomBar、FloatingActionButton 和 Drawer) 提供槽位。使用 Scaffold 時,您可以確保這些組件能夠正確放置并協同工作。而在 Wear OS 中,它也有著專屬的版本,除了同移動版相同的 content 組件之外,額外提供了以下三個主要組件:
△?Wear Scaffold 中的三個主要組件
TimeText: 可以將時間置于屏幕的頂部,我們已經介紹過它,具體請參考上文中關于 TimeText 的部分;
Vignette: 可在屏幕周圍為您提供漂亮的暈影效果,如上圖中所示;
PositionIndicator: 也稱為滾動指示器,是屏幕右側的指示符,用于根據您傳入的狀態對象類型顯示當前指示符的位置。將它放置于 Scaffold 中是由于屏幕是弧形的,因此位置指示器需要位于表盤中央 (Scaffold),而不僅僅是在視口 (viewport) 中央。否則,指示器可能會被截斷。
Scaffold 設計
△Scaffold 設計層級
在進行 Scaffold 的設計時,請參考上圖中的層級順序進行考慮,首先要做的是對 App 進行設置,其次是設置 MaterialTheme 來自定義一些應用的外觀和風格,緊接著是考慮如何放置 Scaffold,最后才是對 Content 的定義。這個順序同在移動端是一樣的,先考慮設置 Theme,再到 Scaffold,接下來看一下如何編寫代碼:
// 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 示例代碼
上述代碼中,由于 positionIndicator 位于 content 之外,因此要將 state 提升到 Scaffold 之上的級別,來避免它在屏幕中被截斷。而在滾動時,可以通過檢查滾動狀態,通過隱藏時間顯示來為屏幕留出更多的空間,還可以根據狀態來關閉或打開 vignette 效果。positionIndicator 支持多種滾動選項,本例中我們使用了 scalingLazyListState,還可以使用很多效果炫酷的其他選項,具體請參考相關文檔。而關于 modifier 和 TimeText 想必不用過多介紹了,而 vignette 的設置其實也很簡單。
Navigation
在本文一開始就提到您需要使用 Wear Navigation 依賴項來替換 Navigation,這里再次強調一下,從技術層面來說您仍可使用 Navigation,但是可能會遇到各種問題,所以還是建議您直接使用已針對 Wear 優化的 Wear Navigation。
△Navigation 設計
Wear Navigation
https://developer.android.google.cn/training/wearables/design/navigation
關于 Navigation 的設計,同 Scaffold 大致相同,采用了和移動版相同的設計,只是在 Scaffold 之下和 Content 之上增加了 SwipeDismissableNavHost,顧名思義該組件支持滑出操作,您可以直接使用與移動應用開發相同的知識來編寫代碼。
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 示例代碼 在上述代碼中,MaterialTheme 和 Scaffold 與之前一樣,但我們創建了一個 navController,并使用了 SwipeDismissable 版本的 rememberSwipeDismissableNavController,名稱非常拗口,但是很容易理解它的功能。然后使用了 SwipeDismissableNavHost 將 startDestination 及其路徑傳遞到控制器中,再設置主屏幕內容即可。您會發現代碼基本上同移動端相同,非常便于理解。
總結
在 Wear OS 中,請確保使用合適的依賴項,替換 Material 并添加 Foundation 依賴,如果使用的是 Navigation 同樣也要進行替換。另外,所有 Compose 構建方面的知識都可以直接應用于 Wear Compose 中,用移動端的開發經驗助您快速構建精美的 Wear 界面。
原文標題:使用 Compose 構建 Wear OS 應用
文章出處:【微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。
-
移動應用
+關注
關注
0文章
64瀏覽量
15546 -
界面
+關注
關注
0文章
59瀏覽量
15623 -
代碼
+關注
關注
30文章
4788瀏覽量
68612
原文標題:使用 Compose 構建 Wear OS 應用
文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發者】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論