###### tags: `android`, `compose`, `column`, `row` ###### title: [Compose 系列 - 2] UI - Layout Column/Row # [Compose 系列 - 2] UI - Layout Column/Row [TOC] ## 前言 上次在[[Compose 系列 - 1] UI - Layout Box & Modifier](/s23tCoUbQ_CN7c5_yNPMHQ) 講述了基本的 Layout: `Box` ,與 UI通用操作: `Modifier`, 接下來就繼續介紹 `Column` & `Row` 沒看過上篇的朋友, 也建議先看一下 ![](https://i.imgur.com/xL4cn5H.png) ## Column & Row Row 和 Column 的操作是類似的. 這邊就以Row 進行示範, Column 反之亦然. 用法: ```kotlin= @Composable fun RowExample() { Row { Text("Hello World!") Text("Hello World!2") } } ``` 文字會並排再一起 ![](https://foso.github.io/Jetpack-Compose-Playground/images/layout/row/RowExample.png =250x) > 圖片來源: [Jetpack compose playground](https://foso.github.io/Jetpack-Compose-Playground/layout/column/) 而Row 有兩個重要的操作: 1. 內容間距 `horizontalArrangement` 2. 垂直位置 `verticalAlignment` --- ### 調整間距: `horizontalArrangement` 1. [SpaceEvenly](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement#SpaceEvenly()) **左, 中, 右, 平均分配空白**: ```kotlin= @Composable fun RowExample() { // 排列方式: #A#B#C# Row(horizontalArrangement = Arrangement.SpaceEvenly) { Text("Hello World!") Text("Hello World!2") } } ``` ![](https://foso.github.io/Jetpack-Compose-Playground/images/layout/row/row_arrangement_space_evenly.png) 2. [SpaceBetween](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement#SpaceBetween) **左右貼齊邊緣, 其餘平均分配**: ```kotlin= @Composable fun RowExample() { // A##B##C Row(horizontalArrangement = Arrangement.SpaceBetween) { ... } } ``` ![](https://i.imgur.com/uPVWz59.png =500x) 3. [SpaceBy](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement#spacedBy(androidx.compose.ui.unit.Dp)) **固定間距**: ```kotlin= @Composable fun RowExample() { Row(horizontalArrangement = Arrangement.SpaceBy(20.dp)) { ... } } ``` ![](https://i.imgur.com/56K11kH.png =x30) 4. [Center](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement#Center) **置中** ```kotlin= @Composable fun RowExample() { Row(horizontalArrangement = Arrangement.Center) { ... } } ``` ![](https://i.imgur.com/l8mLTSl.png =500x) 更多操作請參考[API 文件](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement) 也可以自定義歐~! :+1: --- ### 垂直位置: `verticalAlignment` 假設Row 現在固定高度 `50dp` ```kotlin= @Composable fun RowExample() { Row(modifier = Modifier.height(50.dp)) { Text("Hello World!") Text("Hello World!2") } } ``` 其內容預設擺放位置是在上方 ![](https://i.imgur.com/LQ4IfFD.png =300x) 可以更改參數: `verticalAlignment` 來改變垂直位置 ```kotlin= @Composable fun RowExample() { Row( modifier = Modifier.height(50.dp), verticalAlignment = Alignment.CenterVertically ) { ... } } ``` ![](https://i.imgur.com/3SGDLgH.png =300x) --- ### RowScope 上次在講 [Box-Scope](https://hackmd.io/s23tCoUbQ_CN7c5_yNPMHQ?both#Special-Scope) 時有提及, `Modifier` 會在特別的 Layout 下有額外的操作, 聰明的你應該已經猜到了Row 有哪些操作: 1. **Modifier.weight(w: Float, fill: Boolean = true)** 2. **Modifier.align(alignment: Alignment.Vertical)** 3. **Modifier.alignBy(alignment: Alignment.Vertical)** & **Modifier.alignByBaseline()** ---- #### Modifier.weight(w: Float, fill: Boolean = true) > 對應原有 `android:layout_weight` 先計算沒有權重的UI 空間後, 將剩餘的空間依照權重進行分配: ```kotlin= @Composable fun WeightSample() { Row(Modifier.fillMaxWidth().height(40.dp)) { Text("text 1w", Modifier.weight(1f).background(Color.LightGray)) Text("text 2w", Modifier.weight(2f).background(Color.Yellow)) Text("text 3w", Modifier.wrapContentSize().background(Color.Cyan)) } } ``` 1. 先行計算 `text 3w` 的寬度 2. 將剩餘空間, 依照 _1:2_ 的比例分配給 `text 1w` & `text 2w` ![](https://i.imgur.com/Az1w2Jq.png) --- 第二個參數`fill`, 意即 ==是否填滿空間== 的意思: ```kotlin= @Composable fun WeightSample() { Row(Modifier.fillMaxWidth().height(40.dp)) { Text("text 1w", Modifier.weight(1f).background(Color.LightGray)) Text("text 2w", Modifier.weight(1f, false).background(Color.Yellow)) } } ``` ![](https://i.imgur.com/DPI527A.png) 上圖可以清楚看到, `text 1w` 佔了一半的空間. 而`text 2w` 雖然也有權重1, 但依舊是原本的大小. --- #### Modifier.align > 對應原有 `android:layout_gravity` 參考 [Box-scope](https://hackmd.io/s23tCoUbQ_CN7c5_yNPMHQ?both#Special-Scope) --- #### Modifier.alignBy & Modifier.alignByBaseline ```kotlin= @Composable fun RowHorizontalAlignmentLineSample() { Row(Modifier.fillMaxHeight()) { // The center of the magenta Box and the baselines of the two texts will be // vertically aligned. Note that alignBy() or alignByBaseline() has to be specified // for all children we want to take part in the alignment. For example, alignByBaseline() // means that the baseline of the text should be aligned with the alignment line // (possibly another baseline) specified for siblings using alignBy or alignByBaseline. // If no other sibling had alignBy() or alignByBaseline(), the modifier would have no // effect. Box( modifier = Modifier .size(80.dp, 40.dp) .alignBy { 0 } // 上緣對齊 text1 的baseline .background(Color.Magenta) ) Text( text = "Text 1", fontSize = 40.sp, modifier = Modifier .alignByBaseline() .background(color = Color.Red) ) Text( text = "Text 2", modifier = Modifier.alignByBaseline().background(color = Color.Cyan) ) } } ``` ![](https://i.imgur.com/rsWI71P.png =400x) `alignByBaseline` 就是對齊文字的基線, 可透過觀察 `text1` & `text2` 得知. `alianBy` 必須在 `alignByBaseline` 出現時才會有效, 其效用是讓 ==該 UI 的垂直高度, 對齊另一個 UI 的 baseLine==. > 在上述例子, `Box`使用`Modifier.alianBy{ 0 }`, 等於讓 **Box 上緣對齊text1 Baseline** Box的 Modifier 若改為 ```kotlin= Box( modifier = Modifier .size(80.dp, 40.dp) // .alignBy { 0 } .alignBy { it.measuredHeight / 2 } .background(Color.Magenta) ) ``` 則Box Center 將會對齊 text1 baseline. ![](https://i.imgur.com/sWrobSx.png =400x) ## Next 恩~,基本UI 介紹完了. ... :thinking_face: 那 `RelativeLayout` 或 `ConstraintLayout` 呢? 放心, 當然有相對應的 `ConstraintLayout` 版本, 他被獨立在另外一個package; 而`RelativeLayout` 本身就跟`ConstraintLayout` 功能重疊, 自然直接被取代了~. <div style="color:#f04c00;">下回介紹: Compose UI - ConstrantLayout 篇</div> ## 延伸閱讀 :::warning :book: - [Exploring Jetpack Compose Column](https://joebirch.co/android/exploring-jetpack-compose-column/) - [官方RowScope API Doc](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/RowScope) ::: ## 環境配置 - Android Studio Arctic Fox | 2020.3.1 Canary 15 :::spoiler > Android Studio Arctic Fox | 2020.3.1 Canary 15 Build #AI-203.7717.56.2031.7321754, built on April 29, 2021 Runtime version: 11.0.10+0-b96-7281165 x86_64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. macOS 10.15.7 GC: G1 Young Generation, G1 Old Generation Memory: 2048M Cores: 8 Registry: external.system.auto.import.disabled=true Non-Bundled Plugins: org.jetbrains.kotlin ::: - compose version:`1.0.0-beta07` - kotlin-gradle-plugin:`1.4.32` - com.android.tools.build:gradle:`7.0.0-beta03`