我們昨天使用了Jetpack Compose創建了一個類似敲木魚系統的APP(小廢物),昨天我們在實作的過程中,只是簡單的將兩個元件放置在APP的中央,今天我們要更進一步的來探討APP中很重要的一個部分Layout(佈局) 系統,Layout是人使用APP第一眼就會注意到的東西,俗話說第一印像占了九成,一個好的Layout不僅能吸引住別人的目光,透過Layout合理的組合你的元件還能讓APP在使用的過程中更加的順手。
Jetpack Compose 提供了非常靈活的 Layout系統,用於安排和排列UI元件。這與傳統的Android XML佈局方式不同,Jetpack Compose是以程式碼的形式來聲明UI,並且它強調聲明式和組合性。接下來我會介紹 Jetpack Compose中一些最常用的佈局設計和概念。
Column
是一個垂直佈局容器,內部的子元件會從上到下依序排列。範例如下
@Composable
fun ColumnExample() {
Column(
verticalArrangement = Arrangement.Center, // 垂直居中排列
horizontalAlignment = Alignment.CenterHorizontally // 水平置中
) {
Text(text = "Item 1")
Text(text = "Item 2")
Text(text = "Item 3")
}
}
verticalArrangement:定義子元件在垂直方向上的排列方式。
horizontalAlignment:定義子元件在水平方向上的對齊方式。
我們將這個程式碼放在我們昨天的Greeting和Button中間,顯示的效果如下
Row
是一個水平佈局容器,內部的子元件會從左到右依序排列。
@Composable
fun RowExample() {
Row(
horizontalArrangement = Arrangement.SpaceBetween, // 在子元件間留空
verticalAlignment = Alignment.CenterVertically // 垂直置中
) {
Text(text = "Item A")
Text(text = "Item B")
Text(text = "Item C")
}
}
我們將這個程式碼放繼續塞進我們的APP裡面,顯示的效果如下
Box
是Jetpack Compose提供的一種 佈局容器,它允許你將多個子元件進行重疊或對齊,類似於Android傳統視圖系統中的 FrameLayout。Box提供了一個簡單而靈活的方式來堆疊和排列內容,並且可以讓你更加輕鬆地控制元件在父容器中的位置。
@Composable
fun BoxExample() {
Box(
modifier = Modifier
.size(200.dp) // 設定 Box 的大小
.background(Color.LightGray), // 設定背景顏色
contentAlignment = Alignment.Center // 設定 Box 內部子元件的對齊方式
) {
Text(text = "Hello Box")
}
}
我們將這個程式碼放繼續塞進我們的APP裡面,顯示的效果如下
下面我們再介紹一些有關於Box的應用方式,舉例來說,我們可以透過Box將我們上面的Column和Row並排在一起,程式碼如下
@Composable
fun BoxWithRowAndColumn() {
Box(
modifier = Modifier
.size(300.dp)
.background(Color.LightGray)
) {
// 左側的 Row
Row(
modifier = Modifier
.align(Alignment.CenterStart) // 將 Row 對齊到 Box 的左側
.padding(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(text = "Item A")
Text(text = "Item B")
Text(text = "Item C")
}
// 右側的 Column
Column(
modifier = Modifier
.align(Alignment.CenterEnd) // 將 Column 對齊到 Box 的右側
.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Item 1")
Text(text = "Item 2")
Text(text = "Item 3")
}
}
}
顯示的效果如下
同時Box也和能其他Box嵌套在一起,如下程式碼所示
@Composable
fun ComplexBoxExample() {
Box(
modifier = Modifier
.size(300.dp)
.background(Color.Gray),
contentAlignment = Alignment.TopCenter
) {
Box(
modifier = Modifier
.size(150.dp)
.background(Color.Blue)
.align(Alignment.Center)
) {
Text(
text = "Nested Box",
color = Color.White,
modifier = Modifier.align(Alignment.Center)
)
}
Text(
text = "Outer Box",
color = Color.White,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(8.dp)
)
}
}
顯示的效果如下
上面再演示基本元件時,為了設置元件的大小以免重疊和出界,我們使用了Modifiers
來設置元件的大小、佈局、外觀以及行為,下面簡單的介紹一下Modifiers會用到的參數
常用的 Modifiers:
Spacer 是一個佔位元件,用來在佈局中增加間距。通常與Row或Column一起使用。
@Composable
fun SpacerExample() {
Column {
Text(text = "Item 1")
Spacer(modifier = Modifier.height(16.dp)) // 添加16dp的垂直間距
Text(text = "Item 2")
}
}
顯示的效果如下
LazyColumn
和LazyRow
是用來顯示大量資料的佈局,類似於傳統的RecyclerView。@Composable
fun LazyColumnExample() {
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp) // 子元件間距
) {
items(100) { index ->
Text(text = "Item $index", modifier = Modifier.padding(16.dp))
}
}
}
顯示的效果如下Spacer
和上面提到的Modifiers.padding()
很像都是用來處理元件之間的間距,但它們的用途和使用情境有所不同,Modifier.padding()
是用來設定元件的內邊距或外邊距。它可以用來在元件的四周增加空間,讓元件與其他元件保持距離。Spacer
是一個專門用來在佈局中增加空白空間的組件。它本身沒有任何內容,僅僅是佔據一定的空間,通常用在佈局中需要在兩個元件之間加入彈性間距的時候。由於他是一個元件因此,他可以使用Modifier.height()
或Modifier.width()
來指定Spacer
的高度或寬度,從而更自由的建構你想要的布局。
ConstraintLayout
是一個高級佈局,提供了更精確的佈局控制,類似於 XML 中的 ConstraintLayout。
通常預設的Jetpack Compose並沒有引入相關的依賴庫,因此會出現Unresolved reference: constraintlayout
的報錯,你需要在你的build.gradle(Module-level,一般是 app 模組)檔案中添加添加了以下依賴項
dependencies {
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
}
在添加完依賴項後,點擊Sync同步你的專案,以確保依賴項正確地被引入。
@Composable
fun ConstraintLayoutExample() {
ConstraintLayout(
modifier = Modifier.fillMaxSize()
) {
val (text1, text2) = createRefs()
Text(
text = "Hello",
modifier = Modifier.constrainAs(text1) {
top.linkTo(parent.top, margin = 16.dp)
start.linkTo(parent.start, margin = 16.dp)
}
)
Text(
text = "World",
modifier = Modifier.constrainAs(text2) {
top.linkTo(text1.bottom, margin = 16.dp)
start.linkTo(text1.start)
}
)
}
}
除了上面這些元件和用法,你還可以使用Layout
函數創建自定義的佈局。範例如下
@Composable
fun CustomLayoutExample(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Layout(
content = content,
modifier = modifier
) { measurables, constraints ->
// 測量所有的子元件
val placeables = measurables.map { measurable ->
measurable.measure(constraints)
}
// 設定佈局的寬高
layout(constraints.maxWidth, constraints.maxHeight) {
// 排列每個元件
var yPosition = 0
placeables.forEach { placeable ->
placeable.placeRelative(x = 0, y = yPosition)
yPosition += placeable.height
}
}
}
}
上面這個Layout
會創建一個垂直佈局,所有子元件會從上到下依次排列,沒有間距,寬度會自動適應到父佈局的最大寬度,高度則根據子元件的高度累積。簡單來說,這個自定義佈局就像一個Column,將內容垂直堆疊在一起。
如果想使用你自訂的Layout,可以像下面一樣
@Composable
fun CustomLayoutDemo() {
CustomLayoutExample(
modifier = Modifier.padding(16.dp) // 你可以傳入 Modifier 來設定 CustomLayoutExample 的修飾
) {
// 傳入多個子組件
Text(text = "First Item", modifier = Modifier.background(Color.Red))
Text(text = "Second Item", modifier = Modifier.background(Color.Green))
Text(text = "Third Item", modifier = Modifier.background(Color.Blue))
}
}
我們創建了一個CustomLayoutDemo組件,並且在其中使用了CustomLayoutExample。我們傳入了三個 Text 元件作為子組件,這些元件將由CustomLayoutExample中的自定義佈局邏輯進行垂直排列。
顯示的效果如下
今天我們簡單介紹了Jetpack Compose的Layout方法,為了後續開發出一個自己看得順眼的APP,今天的內容十分的重要,明天我們要結合這幾天的內容,做一個簡單的計算機APP來為第一週的複習內容做一個結尾,感謝你能看到這邊,讓我們明天再見。