本頁說明如何處理尺寸,並提供彈性靈活的回應式功能 透過現有的 Glance 元件使用 Glance 版面配置
使用Box
、Column
和 Row
Glance 有三個主要的可組合函式版面配置:
Box
:將元素放在另一個元素上。這會轉譯為RelativeLayout
。Column
:將元素沿著垂直軸相鄰。可翻譯 設為直向的LinearLayout
。Row
:將元素沿著水平軸相鄰。可翻譯 轉換為水平方向的LinearLayout
。
Glance 支援 Scaffold
物件。放置您的Column
、Row
和
指定 Scaffold
物件中的 Box
可組合函式。
![欄、列和方塊版面配置的圖片。](https://developer.android.com/static/develop/ui/compose/images/column_row_box.png?authuser=0000&hl=zh-tw)
這些可組合函式分別可讓您定義垂直和水平對齊方式 內容以及寬度、高度、粗細或邊框間距限制 修飾符。此外,每個子項都可以定義修飾符來變更空格 以及上層刊登位置
以下範例說明如何建立 Row
,以便平均分配
其子項的水平,如圖 1 所示:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Row
會填滿可用寬度上限,因為每個子項都相同
就會平均共用可用空間您可以設定不同的權重
大小、邊框間距或對齊方式,以配合需求調整版面配置。
使用可捲動版面配置
提供回應式內容的另一種方式是將其設為可捲動。這是
透過 LazyColumn
可組合函式執行這些動作這個可組合函式可讓您定義
。
以下程式碼片段說明在
LazyColumn
。
您可以提供項目數量:
// Remember to import Glance Composables // import androidx.glance.appwidget.layout.LazyColumn LazyColumn { items(10) { index: Int -> Text( text = "Item $index", modifier = GlanceModifier.fillMaxWidth() ) } }
提供個別項目:
LazyColumn { item { Text("First Item") } item { Text("Second Item") } }
提供項目的清單或陣列:
LazyColumn { items(peopleNameList) { name -> Text(name) } }
您也可以合併使用上述範例:
LazyColumn { item { Text("Names:") } items(peopleNameList) { name -> Text(name) } // or in case you need the index: itemsIndexed(peopleNameList) { index, person -> Text("$person at index $index") } }
請注意,先前的程式碼片段並未指定 itemId
。指定
itemId
有助提升效能並維持捲動頁面
透過清單位置,以及從 Android 12 以上版本更新 appWidget
(適用於
例如新增或移除清單中的項目時)。以下範例
說明如何指定 itemId
:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
定義 SizeMode
AppWidget
尺寸可能會因裝置、使用者選擇或啟動器而異。
因此,請務必按照提供
彈性的小工具版面配置頁面。Glance 利用 SizeMode
簡化這件事。
定義和 LocalSize
值以下各節將說明
。
SizeMode.Single
預設模式為 SizeMode.Single
。表示只有一種
內容;也就是即使 AppWidget
可用的大小有所變更
內容大小維持不變
class MyAppWidget : GlanceAppWidget() { override val sizeMode = SizeMode.Single override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be the minimum size or resizable // size defined in the App Widget metadata val size = LocalSize.current // ... } }
使用這種模式時,請確認以下事項:
- 中繼資料值的最小和最大尺寸必須正確定義 配合內容大小
- 在預期大小範圍內,內容的靈活度夠高。
一般來說,只要符合下列任一條件,建議您使用這個模式:
a) AppWidget
有固定大小,或
b) 調整大小時,不會變更其內容。
SizeMode.Responsive
這個模式相當於提供回應式版面配置,以允許
GlanceAppWidget
可定義一組符合特定條件的回應式版面配置
大小。針對每個已定義的大小,系統會建立內容並對應至特定的
AppWidget
建立或更新時的大小。接著,系統會選取
選出最適當的尺寸。
舉例來說,在目的地 AppWidget
中,您可以定義三種大小
內容:
class MyAppWidget : GlanceAppWidget() { companion object { private val SMALL_SQUARE = DpSize(100.dp, 100.dp) private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp) private val BIG_SQUARE = DpSize(250.dp, 250.dp) } override val sizeMode = SizeMode.Responsive( setOf( SMALL_SQUARE, HORIZONTAL_RECTANGLE, BIG_SQUARE ) ) override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be one of the sizes defined above. val size = LocalSize.current Column { if (size.height >= BIG_SQUARE.height) { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) } Row(horizontalAlignment = Alignment.CenterHorizontally) { Button() Button() if (size.width >= HORIZONTAL_RECTANGLE.width) { Button("School") } } if (size.height >= BIG_SQUARE.height) { Text(text = "provided by X") } } } }
在上一個範例中,系統會呼叫 provideContent
方法三次,並
就會對應至已定義的大小
- 在第一次呼叫中,大小評估為
100x100
。內容沒有 包括額外按鈕,以及頂端和底部文字。 - 在第二次呼叫中,大小評估為
250x100
。內容包括 額外按鈕,但不包括頂端和底部文字。 - 在第三次呼叫中,大小評估為
250x250
。內容包括 多餘按鈕,以及文字。
SizeMode.Responsive
是其他兩種模式的組合,可讓您
在預先定義範圍內定義回應式內容。一般而言,這個模式
執行效果更好,且可在 AppWidget
調整大小時更順暢。
下表顯示尺寸值,具體取決於 SizeMode
和
AppWidget
的可用大小:
可用大小 | 105 x 110 | 203 x 112 | 72 x 72 | 203 x 150 |
---|---|---|---|---|
SizeMode.Single |
110 x 110 | 110 x 110 | 110 x 110 | 110 x 110 |
SizeMode.Exact |
105 x 110 | 203 x 112 | 72 x 72 | 203 x 150 |
SizeMode.Responsive |
80 x 100 | 80 x 100 | 80 x 100 | 150 x 120 |
* 確切的值僅供示範之用。 |
SizeMode.Exact
SizeMode.Exact
等同於提供確切的版面配置,
每次可用的 AppWidget
大小時,要求 GlanceAppWidget
內容
變更 (例如使用者調整主畫面上的 AppWidget
大小時)。
舉例來說,在目標小工具中,您可以在 可用寬度大於某個值。
class MyAppWidget : GlanceAppWidget() { override val sizeMode = SizeMode.Exact override suspend fun provideGlance(context: Context, id: GlanceId) { // ... provideContent { MyContent() } } @Composable private fun MyContent() { // Size will be the size of the AppWidget val size = LocalSize.current Column { Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp)) Row(horizontalAlignment = Alignment.CenterHorizontally) { Button() Button() if (size.width > 250.dp) { Button("School") } } } } }
這個模式提供更多彈性 注意事項:
- 每次大小變更時,都必須完整重新建立
AppWidget
。這個 如果內容複雜,可能會導致效能問題和使用者介面跳動。 - 可用大小可能會因啟動器的實作方式而異。 舉例來說,如果啟動器未提供大小清單,則 可能的大小
- 在 Android 12 以下版本的裝置上,大小計算邏輯可能並不適用 情境。
一般而言,如果 SizeMode.Responsive
無法使用,應使用這個模式
(也就是說,少數的回應式版面配置不適合)。
取得實用資源
使用 LocalContext.current
存取任何 Android 資源,如
範例:
LocalContext.current.getString(R.string.glance_title)
建議您直接提供資源 ID,以減少最終圖像的大小
RemoteViews
物件,並啟用動態資源,例如動態資源
顏色。
可組合元件和方法接受使用「提供者」的資源,例如
ImageProvider
,或是使用超載方法
GlanceModifier.background(R.color.blue)
。例如:
Column( modifier = GlanceModifier.background(R.color.default_widget_background) ) { /**...*/ } Image( provider = ImageProvider(R.drawable.ic_logo), contentDescription = "My image", )
處理文字
Glance 1.1.0 包含用來設定文字樣式的 API。使用以下字詞設定文字樣式:
TextStyle 類別的 fontSize
、fontWeight
或 fontFamily
屬性。
fontFamily
支援所有系統字型,如以下範例所示,但
系統不支援在應用程式中使用自訂字型:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
新增複合按鈕
Android 12 導入複合按鈕。資訊一覽支援回溯功能 與以下類型的複合按鈕相容:
這些複合按鈕會顯示可點擊的檢視區塊,代表 「已勾選」時間。
var isApplesChecked by remember { mutableStateOf(false) } var isEnabledSwitched by remember { mutableStateOf(false) } var isRadioChecked by remember { mutableStateOf(0) } CheckBox( checked = isApplesChecked, onCheckedChange = { isApplesChecked = !isApplesChecked }, text = "Apples" ) Switch( checked = isEnabledSwitched, onCheckedChange = { isEnabledSwitched = !isEnabledSwitched }, text = "Enabled" ) RadioButton( checked = isRadioChecked == 1, onClick = { isRadioChecked = 1 }, text = "Checked" )
當狀態變更時,就會觸發提供的 lambda。您可以將 檢查狀態,如以下範例所示:
class MyAppWidget : GlanceAppWidget() { override suspend fun provideGlance(context: Context, id: GlanceId) { val myRepository = MyRepository.getInstance() provideContent { val scope = rememberCoroutineScope() val saveApple: (Boolean) -> Unit = { scope.launch { myRepository.saveApple(it) } } MyContent(saveApple) } } @Composable private fun MyContent(saveApple: (Boolean) -> Unit) { var isAppleChecked by remember { mutableStateOf(false) } Button( text = "Save", onClick = { saveApple(isAppleChecked) } ) } }
您也可以將 colors
屬性提供給 CheckBox
、Switch
和
RadioButton
自訂顏色:
CheckBox( // ... colors = CheckboxDefaults.colors( checkedColor = ColorProvider(day = colorAccentDay, night = colorAccentNight), uncheckedColor = ColorProvider(day = Color.DarkGray, night = Color.LightGray) ), checked = isChecked, onCheckedChange = { isChecked = !isChecked } ) Switch( // ... colors = SwitchDefaults.colors( checkedThumbColor = ColorProvider(day = Color.Red, night = Color.Cyan), uncheckedThumbColor = ColorProvider(day = Color.Green, night = Color.Magenta), checkedTrackColor = ColorProvider(day = Color.Blue, night = Color.Yellow), uncheckedTrackColor = ColorProvider(day = Color.Magenta, night = Color.Green) ), checked = isChecked, onCheckedChange = { isChecked = !isChecked }, text = "Enabled" ) RadioButton( // ... colors = RadioButtonDefaults.colors( checkedColor = ColorProvider(day = Color.Cyan, night = Color.Yellow), uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue) ), )
其他元件
Glance 1.1.0 包含其他元件的發布內容,如 資料表:
名稱 | 圖片 | 參考資料連結 | 其他注意事項 |
---|---|---|---|
實心按鈕 |
![]() |
元件 | |
外框按鈕 |
![]() |
元件 | |
圖示按鈕 |
![]() |
元件 | 主要 / 次要 / 純圖示 |
標題列 |
![]() |
元件 | |
Scaffold | Scaffold 和標題列是同一個示範。 |
如要進一步瞭解特定設計,請參閱本章節中的元件設計 設計套件。