iT邦幫忙

2021 iThome 鐵人賽

DAY 3
3
Mobile Development

認真學 Compose - 對 Jetpack Compose 的問題與探索系列 第 3

D03 / 怎麼擺放我的畫面 - Layout & Alignment

今天大概會聊到的範圍

  • basic layout
  • arrangement & alignment

在 Compose 之中,我們有三個可以乘載其他 component 的基礎 container。他們分別是縱向排列的 Column 、橫向排列的 Row  以及圖層式排列的 Box 。透過這三個 container,我們可以擺出各式各樣的畫面。

https://ithelp.ithome.com.tw/upload/images/20210917/20141597QKLJk0lcdt.png
(image source: Compose layout basics | Android Developers)

在擺放 Layout 時,大致可以透過兩個面向來異動 component 在 container 中的位置:

  1. 從 container 一次異動所有的 item
  2. 對單個 component(item) 調整他在 container 內的位置。

很類似原本的 xml 排版中, gravity  和 layout_gravity 這兩個 attribute 的行為。

註:這邊會用 container 來代表在 Row / Column 這種可以裝其他 composable 的 composable。而裝在內 composable 則的會用 item 來稱呼。

從 Container 控制

以 Row 舉例,Row 中的 item 會是橫向排列。不同的 item 的高度不同時,就有怎麼對齊的問題。
透過 Row 的 verticalAlignment 這個參數,可以定義對齊方式。

常見的有對齊方式有:Alignment.Bottom, Alignment.TopAlignment.CenterVertically

@Preview
@Composable
fun `Row Alignment Bottom`() {
    Row(
        verticalAlignment = Alignment.Bottom, // <<< 
        modifier = Modifier
            .height(130.dp)
            .fillMaxWidth()
    ) {
        ChildA()
        ChildB()
        ChildC()
    }
}
Alignment.Bottom Alignment.CenterVertically Alignment.Top
Alignment.Bottom Alignment.CenterVertically Alignment.Top

另外,還可以透過 BiasAlignment.Vertical(bias) 在 1 ~ -1 之間的某一個特定比例做對齊 ( -1 = Top , 1 = Bottom, 0 = Center )

@Preview
@Composable
fun `Row Alignment Bias Vertical`() {
    Row(
        verticalAlignment = BiasAlignment.Vertical(-0.4f),
        modifier = Modifier
            .height(130.dp)
            .fillMaxWidth()
    ) {
        ChildA()
        ChildB()
        ChildC()
    }
}
BiasAlignment.Vertical
BiasAlignment.Vertical

除了 Alignment 外,還有 Arrangement ,Arrangment 調整的是 item 在 container 擺放的位置。最基本的是 StartEnd ,代表著 item 從 container 中最左 or 最右開始擺放。Center 則是代表所有 item 集合在最中間

@Preview
@Composable
fun `Row Arrangement Start`() {
    Row(
        horizontalArrangement = Arrangement.Start, // <<< 
        modifier = Modifier
            .height(130.dp)
            .fillMaxWidth()
    ) {
        ChildA()
        ChildB()
        ChildC()
    }
}
Arrangement.Start Arrangement.End Arrangement.Center
Arrangement.Start Arrangement.End Arrangement.Center

另外,還有 SpaceEvently , SpaceBetweenSpaceAround 三種設定可以將物件平均分佈在 container 內。

SpaceEvently 就是普通的平均分佈。SpaceBetween 也是平均分佈,但是兩端不留空間。最後 SpaceAround 是每個 item 的兩邊都有一個間隔,意味著 item 與 item 間的空間會是最兩端 item 與 container 邊界間的兩倍

Arrangement.SpaceEvently Arrangement.SpaceBetween Arrangement.SpaceAround
Arrangement.SpaceEvently Arrangement.SpaceBetween Arrangement.SpaceAround

Column 也有完全相同的結構只是方向改成垂直的,這邊就不多做介紹。


從 Item 控制

有時候,我們只需要某一個 item 擺在特殊的位置,這時候可以對特定 item 設定 align 這個 modifier 。align 在對應的 container 中能使用的參數與稍早提到的 alignment 參數是相同的。在 Row 中可以使用 Top / Bottom / CenterVerticallyColumn 中可以做 Start / End / CenterHorizontally。在 Box 中擺放的位置更自由,有上下左右、四角及中間等九個位子(如下圖)。當然,前面提到的 BiasAlignment 也是可以使用的。

@Preview(group = "item arrangement")
@Composable
fun `Arrangement Item`() {
    Box(
        modifier = Modifier.size(360.dp)
    ) {
        Item(name = "TopStart", modifier = Modifier.align(Alignment.TopStart))
        Item(name = "TopCenter", modifier = Modifier.align(Alignment.TopCenter))
        Item(name = "TopEnd", modifier = Modifier.align(Alignment.TopEnd))
        Item(name = "CenterStart", modifier = Modifier.align(Alignment.CenterStart))
        Item(name = "Center", modifier = Modifier.align(Alignment.Center))
        Item(name = "CenterEnd", modifier = Modifier.align(Alignment.CenterEnd))
        Item(name = "BottomStart", modifier = Modifier.align(Alignment.BottomStart))
        Item(name = "BottomCenter", modifier = Modifier.align(Alignment.BottomCenter))
        Item(name = "BottomEnd", modifier = Modifier.align(Alignment.BottomEnd))
    }
}

https://ithelp.ithome.com.tw/upload/images/20210917/20141597j22MVabZ67.png


有了這些調整位置的方式、基本的 padding、再加上對 Layout 的嵌套,已經可以大致排出各種需求了。


上一篇
D02 / 怎麼看到我在寫什麼? - @Preview
下一篇
D04 / 可不可以用 ConstraintLayout - ConstraintLayout
系列文
認真學 Compose - 對 Jetpack Compose 的問題與探索30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言