修飾元可用於裝飾或增強可組合元件。修飾元可以讓您執行下列操作:
- 變更可組合元件的大小、版面配置、行為和外觀
- 新增資訊,例如無障礙標籤
- 處理使用者輸入內容
- 新增高等級互動,例如讓元素可供點擊、可捲動、可拖曳或可縮放
修飾元是標準的 Kotlin 物件。呼叫其中一個 Modifier
類別函式以建立修飾元:
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
將這些函式鏈結在一起即可進行撰寫:
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
請注意,以上程式碼將多個不同的修飾符函式搭配使用。
padding
會在元素周圍放置空格。fillMaxWidth
提供可組合的父項寬度上限。
最佳做法是讓「所有」可組合函式接受 modifier
參數,然後將該修飾符傳遞至第一個輸出 UI 的子項。
如此一來,程式碼就更容易重複使用,且行為更易於預測,更直覺易懂。詳情請參閱 Compose API 指南:元素接受並修改修飾元參數。
修飾符的順序很重要
修飾元函式的順序 很重要。由於每個函式都會對前一個函式傳回的 Modifier
進行變更,因此序列會影響最終結果。範例如下:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
在以上程式碼中,整個區域都可點擊,包括周圍的邊框間距,這是因為在 clickable
修飾符「之後」才套用 padding
修飾符。如果修飾元順序相反,padding
新增的空格不會回應使用者輸入的內容:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
內建修飾元
Jetpack Compose 提供內建修飾元清單,可協助您裝飾或增強可組合元件。以下列舉一些常見的修飾元,可用來調整您的版面配置。
padding
和size
根據預設,Compose 中的版面配置會包裝它們的子項。不過,您可以使用 size
修飾符設定大小:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
請注意,如果指定的版面配置大小不符合版面配置的父項限制,系統可能不會採用指定的大小。如果無論輸入限制為何,您都必須修正可組合元件的大小,那麼請使用 requiredSize
修飾元:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
在這個範例中,即使父項 height
設為 100.dp
,Image
的高度也會是 150.dp
,因為 requiredSize
修飾元有優先優勢。
如果您希望子項版面配置填滿父項允許的所有可用高度,請新增 fillMaxHeight
修飾元(Compose 也提供 fillMaxSize
和 fillMaxWidth
):
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
如要在元素周圍加上邊框間距,請設定 padding
修飾符。
如果您想在文字基準線上方加上邊框間距,以便達成
使用從版面配置頂端到基準的特定距離
paddingFromBaseline
修飾符:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
偏移
如要根據版面配置的原始位置調整版面配置,請在前面加入
offset
修飾符,並設定 x 和 Y 軸的偏移值。
偏移值可以是正數,也可以是非正數。差異
padding
和 offset
是將 offset
新增至可組合項時,並不會
變更測量值:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
系統會按照版面配置方向水平套用 offset
修飾元。
在 從左到右 的情境中,正的 offset
會將元素向右移動,而在 向右到左 的內容中,它將元素向左移動。
如果您需要設定位移值,而不考慮版面配置方向,請參閱 absoluteOffset
修飾元,該修飾元中的正位移值一律會將元素向右移動。
offset
修飾符會提供兩個超載:offset
會將偏移值用做為參數,而 offset
則會擷取 lambda。如要進一步瞭解使用上述各項功能的時機及最佳化方式
請參閱
Compose 效能 - 盡可能延遲讀取時間一節。
Compose 中的範圍安全性
在 Compose 中,一些修飾符只有在套用於某些可組合元件的子項時才可使用。為此,Compose 會透過自訂範圍強制執行。
舉例來說,如果您想讓子項和 Box
父項一樣大,但不要使用
影響 Box
的大小,請使用
matchParentSize
修飾符matchParentSize
僅適用於 BoxScope
。因此,這只能用於 Box
父項中的子項。
範圍安全性可避免新增在其他平台不支援的修飾符 可組合函式和範圍,節省反覆嘗試和出錯的時間。
限定範圍的修飾元可用來通知父項,以便其瞭解一些關於子項的資訊。這通常被稱為父項資料修飾元。這些修飾符的內部結構與一般用途的修飾符不同,但從使用的角度來看,這些差異並不重要。
Box
的matchParentSize
如上所述,如果要讓子項版面配置與父項相同大小
Box
,在不影響 Box
大小的情況下,請使用 matchParentSize
修飾符。
請注意,matchParentSize
僅適用於 Box
範圍,因此僅適用於 Box
可組合元件的 直接子項。
在以下範例中,子 Spacer
從父 Box
取得其大小,而後者的大小是從最大的子 ArtistCard
中擷取的。
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
如果使用 fillMaxSize
而不是 matchParentSize
,Spacer
會取得父項允許的所有可用空間,進而導致父項能夠展開及填滿所有可用的空間。
Row
和Column
的weight
如前文 邊框間距和大小 一節的說明,根據預設,可組合元件的大小是由其包裝的內容定義的。您可以使用僅由 RowScope
和 ColumnScope
提供的 weight
修飾元,靈活地在父項範圍內設定可組合元件的大小。
讓我們來看看包含兩個 Box
可組合元件的 Row
。
第一個方塊是第二個 weight
的兩倍,因此在
寬度。由於 Row
的寬度為 210.dp
,因此第一個 Box
寬為 140.dp
,第二個為 70.dp
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
擷取及重複使用修飾符
您可以將多個修飾符鏈結在一起來裝飾或
增強可組合函式此鏈結是透過 Modifier
介面建立
代表已排序且不可變動的單一 Modifier.Elements
清單。
每個 Modifier.Element
都代表個別行為,例如版面配置、繪圖
所有手勢相關行為、焦點和語意行為
以及裝置輸入事件這些元素的排序相當重要:系統會按加入的先後次序套用修飾符元素。
有時候,在 多個可組合函式,方法是將這類可組合項擷取至變數,再提升至 範圍提升程式碼的可讀性,或改善應用程式的 成效有幾個:
- 重組程序發生時,系統不會重複修飾符的重新分配程序 以使用
- 修飾符的鏈結或會十分長和複雜,因此重複使用相同的鏈結執行個體,可減輕 Compose 執行階段在比較這些執行個體時的工作負載
- 這項擷取操作可提升程式碼的簡潔性、一致性和可維護性 程式碼集
重複使用修飾符的最佳做法
建立並擷取自己的 Modifier
鏈結,以便在多個項目中重複使用
可組合元件您可以直接儲存修飾符
是類似資料的物件
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
觀察經常變更的狀態時,擷取並重複使用修飾符
觀察可組合項中經常變動的狀態 (例如動畫狀態或 scrollState
) 時,系統或會執行大量重組程序。在此情況下,系統會在每次重組時分配修飾符
每次影格都會出現以下情形:
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
您可改為建立、擷取並重複使用相同的修飾符執行個體 並將其傳遞至可組合函式,如下所示:
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
擷取及重複使用未限定範圍的修飾符
修飾符可不限定範圍,或限定至特定 可組合函式。針對未限定範圍的修飾符,您可以輕鬆地擷取這類修飾符 做為簡易變數的任何可組合項:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
這個做法尤其適合與 Lazy 版面配置搭配使用。大多數 建議您將所有可能數量龐大的項目 完全相同的修飾符:
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
擷取及重複使用限定範圍修飾符
處理範圍限定於特定可組合項的修飾符時,您可以將其擷取至最高層級,並在合適的情況下重複使用:
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
您應該只將已擷取的限定範圍修飾符傳遞至相同範圍的直接子項。請參閱「範圍安全性: Compose,進一步瞭解這個做法的重要性:
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
進一步鏈結已擷取的修飾符
您可以呼叫 .then()
函式,進一步鏈結或附加已擷取的修飾符鏈結:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
請務必留意,修飾符的順序很重要!
瞭解詳情
我們提供修飾元的完整清單,以及其中的參數和範圍。
如要進一步瞭解如何使用修飾符,您也可以參考 Compose 程式碼研究室的基本版面配置,或參閱 Now in Android 存放區。
如要進一步瞭解自訂修飾符及其建立方式,請參閱 請參閱「自訂版面配置 - 使用版面配置修飾符」說明文件。
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- Compose 版面配置的基本概念
- 編輯者動作 {:#editor-actions}
- 自訂版面配置 {:#custom-layouts }