一、布局
官網對于Compose布局的描述
可組合函式是 Compose 的基本構建塊,可組合函式是一種發出
Unit的函式,用于描述界面中的某一部分,該函式接受一些輸入并生成螢屏上顯示的內容,如需詳細了解可組合項,請參閱 Compose 構思模型檔案,
一個可組合函式可能會發出多個界面元素,不過,如果您未提供有關如何排列這些元素的指導,Compose 可能會以您不喜歡的方式排列它們,
當我們嘗試著像如下撰寫代碼時
@Composable
fun MainPage() {
Text(text = "Hello,Jetpack Compose!")
Text(text = "hello,jetpack compose!")
}
在預覽視圖中會發現兩個Text重疊了

在xml中,我們可以用各種布局方式來排列/約束視圖元素的位置,那么在Compose 中如何實作呢?Compose中有沒有類似于LinearLayout、FrameLaoyout、ConstraintLayout 的東西呢?
答案是:必然有,
在許多情況下,您只需使用 Compose 的標準布局元素即可,
通過以下幾種布局方式,基本可以滿足日常的開發布局需求,
1. Row
Row可以理解為Xml布局中LinearLayout的horizontal模式,例如:
@Composable
fun MainPage() {
Row(){
Text(text = "Hello")
Text(text = ",")
Text(text = "jetpack compose!")
}
}

通過Row的原始碼可以看到我們還可以傳遞如下幾個引數:
@Composable
inline fun Row(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
content: @Composable RowScope.() -> Unit
) {
...
}
| 引數 | 型別 | 默認值 | 含義 |
|---|---|---|---|
| modifier | Modifier | Modifier | 布局的修飾符 |
| horizontalArrangement | Arrangement.Horizontal | Arrangement.Start | 布局子級的 水平 放置方式,默認從布局開始往布局結束方向放置 |
| verticalAlignment | Alignment.Vertical | Alignment.Top | 布局子級的 垂直 對其方式,默認從布局頂部對齊 |
例如:

需要注意的是,和LinearLayout一樣,超出布局設定的最大寬度或高度的視圖將不可見
2. Column
Column可以理解為Xml布局中LinearLayout的vertical模式,例如:
@Composable
fun MainPage() {
Column(Modifier.padding(Dp(50f))) {
Text(text = "Hello")
Text(text = ",")
Text(text = "jetpack compose!")
}
}
通過Column的原始碼可以看到我們還可以傳遞如下幾個引數:
@Composable
inline fun Column(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
) {
...
}
| 引數 | 型別 | 默認值 | 含義 |
|---|---|---|---|
| modifier | Modifier | Modifier | 布局的修飾符 |
| verticalArrangement | Arrangement.Vertical | Arrangement.Top | 布局子級的 豎直 放置方式,默認從布局頂部往布局底部方向放置 |
| horizontalAlignment | Alignment.Horizontal | Alignment.Start | 布局子級的 水平 對其方式,默認從布局開始對齊 |
Column有和Row同樣的問題,注意用于修飾Column子級放置和對其方式和Row的引數是不一樣的
3. Box
Box可以理解為Xml布局中FrameLayout,例如:
@Composable
fun MainPage() {
Box(Modifier.size(Dp(300f), Dp(150f)),
contentAlignment = Alignment.Center) {
Box(modifier = Modifier
.background(MaterialTheme.colors.error)
.size(Dp(200f), Dp(100f)))
Box(modifier = Modifier
.background(MaterialTheme.colors.secondary)
.size(Dp(100f), Dp(50f)))
Text(text = "hello,jetpack compose!")
}
}

通過Column的原始碼可以看到我們還可以傳遞如下幾個引數:
@Composable
inline fun Box(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
) {
...
}
| 引數 | 型別 | 默認值 | 含義 |
|---|---|---|---|
| modifier | Modifier | Modifier | 布局的修飾符 |
| contentAlignment | Alignment | Alignment.TopStart | Box 內的默認對齊方式 |
| propagateMinConstraints | Boolean | false | 傳入的最小約束是否應傳遞給內容, |
4. BoxWithConstraints
如需了解來自父項的約束條件并相應地設計布局,您可以使用
BoxWithConstraints,您可以在內容 lambda 的作用域內找到測量約束條件,
BoxWithConstraints與 Box 使用方式完全一致,只是如官方所說,可以測量約束條件,例如:
@Composable
fun MainPage1() {
BoxWithConstraints {
Text("My minHeight is $maxHeight while my maxWidth is $maxWidth")
}
}
在其作用域內可以拿到 BoxWithConstraints的最大最小寬高資訊,
5. ConstraintLayout
ConstraintLayout 其實就是Xml布局中的 ConstraintLayout,我們來看官方的描述
ConstraintLayout有助于根據可組合項的相對位置將它們放置在螢屏上,它是使用多個嵌套Row、Column、Box和自定義布局元素的替代方案,在實作對齊要求比較復雜的較大布局時,ConstraintLayout很有用,
注意:在 View 系統中,建議使用
ConstraintLayout來創建復雜的大型布局,因為扁平視圖層次結構比嵌套視圖的性能更好,不過,這在 Compose 中不是什么問題,因為它能夠高效地處理較深的布局層次結構,
注意:是否將
ConstraintLayout用于 Compose 中的特定界面取決于開發者的偏好,在 Android View 系統中,使用ConstraintLayout作為構建更高性能布局的一種方法,但這在 Compose 中并不是問題,在需要進行選擇時,請考慮ConstraintLayout是否有助于提高可組合項的可讀性和可維護性,
可以看出,雖然官方提供了ConstraintLayout,但并不推薦在Compose中使用,xml中使用ConstraintLayout的根本目的是為了減少視圖嵌套層級從而提升android的頁面繪制性能,在Compose中不存在視圖嵌套這一概念,所以是否使用ConstraintLayout,需要考慮個人習慣和 ConstraintLayout 是否有助于提高可組合項的可讀性和可維護性,
在使用ConstraintLayout前,需要在 build.gradle 中添加以下依賴項:
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha08"
Compose 中的 ConstraintLayout 支持 DSL:
- 參考是使用
createRefs()或createRefFor()創建的,ConstraintLayout中的每個可組合項都需要有與之關聯的參考, - 約束條件是使用
constrainAs()修飾符提供的,該修飾符將參考作為引數,可讓您在主體 lambda 中指定其約束條件, - 約束條件是使用
linkTo()或其他有用的方法指定的, parent是一個現有的參考,可用于指定對ConstraintLayout可組合項本身的約束條件,
依舊看下實體:
@Composable
fun MainPage() {
ConstraintLayout(Modifier.size(200.dp)) {
val (button, text) = createRefs()
Button(
onClick = { },
modifier = Modifier.constrainAs(button) {
top.linkTo(parent.top)
start.linkTo(parent.start)
end.linkTo(parent.end)
bottom.linkTo(parent.bottom)
},
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.secondary,
contentColor = Color.White
)
) {
Text("Button")
}
Text("Text", Modifier.constrainAs(text) {
top.linkTo(button.top)
})
}
}

可以看出,用法和xml中基本一致,代碼中button被約束到視圖中心,text的頂部對齊button的頂部,
6. Spacer
一個空白的視圖,官方并未提供類似于Xml中margin的屬性,可能推薦用這個替代吧,例如:
@Composable
fun MainPage() {
Row {
Box(Modifier.size(100.dp).background(Color.Red))
Spacer(Modifier.width(20.dp))
Box(Modifier.size(100.dp).background(Color.Magenta))
Spacer(Modifier.weight(1f))
Box(Modifier.size(100.dp).background(Color.Black))
}
}

二、最后
好記性不如爛筆頭,初識 Jetpack Compose 系列是我自己的學習筆記,在加深知識鞏固的同時,也可以鍛煉一下寫作技能,文章中的內容僅作參考,如有問題請留言指正,
2.滾動視圖
上面說到 Row 和 Column 有如果子視圖超出父視圖邊界,則無法展示的問題;在xml中一般使用ScrollView以支持視圖滾動,相應的,在Compose中可以由LazyRow、LazyColumn實作,但他倆的功能不僅僅只是用來實作視圖滾動,所以在本文就不展開了,LazyRow、LazyColumn預計將會有后續的widget篇中具體描述,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/298144.html
標籤:其他
