owned this note
owned this note
Published
Linked with GitHub
###### tags: `android`, `compose`, `functional programming`
###### title: [Compose 系列 - 1] UI - Layout Box & Modifier
# [Compose 系列 - 1] UI - Layout Box & Modifier
[TOC]
## 主旨
構築畫面, 需要兩種 UI種類:
1. 責顯示畫面的 **View**
2. 負責佈局的 **ViewGroup**.
此篇以**ViewGroup** 的部分進行介紹:
<div style="color:#f04c00;">在Compose 的世界裡, 如何進行畫面的佈局</div>
---
## Compose Layout

:::warning
:book: 參考自:
[Compose-Layout 官網介紹](https://developer.android.com/jetpack/compose/layout)
:::
基本的 Layout 為上述三種:
1. Column: 垂直排列
2. Row: 水平排列
3. Box: 區域內放置 (想不太出來中文的解釋)
我們就從最簡單的 Box 來開始介紹, 關於Layout 的這檔事
### Box
其實他就是相對應的 `FragmentLayout`. 因此他能做的事情非常簡單,
就是將Box 底下的畫面, 擺放在八個方位: **上下左右 和 四角落**
```kotlin=
@Composable
fun BoxSample() {
Box { // BoxScope
Text("Hello World")
}
}
```
預設是出現在左上角

若想更改位置, 比如我想將文字至正上方, 此時需使用`Modifier`
```kotlin=
@Composable
fun BoxSample() {
Box { // BoxScope
Text(
modifier = Modifier.align(Alignment.TopCenter),
text = "Hello World"
)
}
}
```
### Modifier 是什麼?
我個人的解釋是: **對 UI 進行通用的操作**
1. 他可以設定大小, 背景, clickEvent, padding, shadow, clip, ... 等 操作.
2. 在特別的Scope 下, 可以進行特有的 動作
---
#### Common
先來解釋第一點:
```kotlin=
@Composable
fun BoxSample() {
Box(modifier = Modifier
.height(40.dp) // 固定高度 40 dp
.wrapContentWidth() // android:layout_width:wrapContent
.padding(10.dp) // padding 10 dp
.background(color = Color.Red)
.clickable { Log.d("log", "box click") }
) { // BoxScope
Text(text = "Hello World")
}
}
```

簡單明瞭.
而操作的順序也是有差的! 比如我將 line: 6, 7 對調:
```kotlin=
@Composable
fun BoxSample() {
Box(modifier = Modifier
.height(40.dp) // 固定高度 40 dp
.wrapContentWidth() // android:layout_width:wrapContent
.background(color = Color.Red)
.padding(10.dp) // padding 10 dp
.clickable { Log.d("log", "box click") }
) { // BoxScope
Text(text = "Hello World")
}
}
```
就會變成
1. render backgroud
2. padding 10dp

甚至還能進行多次的`padding`操作:
```kotlin=
@Composable
fun BoxSample() {
Box(modifier = Modifier
.height(40.dp) // 固定高度
.wrapContentWidth() // android:layout_width:wrapContent
.padding(5.dp)
.background(color = Color.Red)
.padding(5.dp)
.clickable { Log.d("log", "box click") }
) { // BoxScope
Text(text = "Hello World")
}
}
```
1. padding 5dp
2. render background
3. padding 5dp

更多操作大家可以去看[API 文件](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)
---
#### Special Scope
關於第二點, 眼尖的各位應該有發現前面的例子上我有註解 `// BoxScope` 的字樣, 在IDE 上應該也會看到提示. 實際上這個lambda 是有傳進一個 `BoxScope` 的 interface. 而在 `BoxScope`內, 可以執行 **屬於Box 的操作**. 比如剛剛講的例子:
```kotlin=
@Composable
fun BoxSample() {
Box { // BoxScope
Text(
modifier = Modifier.align(Alignment.TopCenter),
text = "Hello World"
)
}
}
```
`Modifier.align(alignment: Alignment)` 是只有在Box 底下可以執行的操作, 而上述例子相當於以前的 `android:layout_gravity="top|center_horizontal"`
## Next
- [[Compose 系列 - 2] UI - Layout Column/Row](/v4x18WsIRfCqCMSFkfQPLQ)
繼續講述, 關於Column 跟 Row 的操作, 基本上跟 也是跟原有的`LinearLayout` 不會相差太遠.
## 環境配置
- 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`