###### 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 ![](https://i.imgur.com/xL4cn5H.png) :::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") } } ``` 預設是出現在左上角 ![](https://i.imgur.com/zX1ocHn.png =200x) 若想更改位置, 比如我想將文字至正上方, 此時需使用`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") } } ``` ![](https://i.imgur.com/JJZxCfT.png) 簡單明瞭. 而操作的順序也是有差的! 比如我將 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 ![](https://i.imgur.com/2WQn16G.png) 甚至還能進行多次的`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 ![](https://i.imgur.com/kqz9LZ3.png) 更多操作大家可以去看[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`