在研究 Compose 元件時,讀者應該有發現,每個元件都有 modifier 這個參數,有時要改變元件的外觀或行為時,就得透過這個參數。但到底 Modifier 是什麼,總覺得有點霧裡看花的感覺。今天的耕讀筆記,就要來好好研究一下在 Compose 裡很重要的 Modifier。
Modifier根據 Jetpack Compose 官方文件,Modifier 可以用在 @Composable 的幾個地方:
在使用 Modifier 時,有幾個值得注意的特點:
Modifier 是標準的 Kotlin Object,使用時直接以 Object 操作即可。Modifier Object 的方法設計支援 Method Chain,開發者可串接多個方法,一次設定多個屬性。Modifier 方法時,順序是有意義的,在使用上要注意呼叫的順序。Modifier 設定背景顏色及不透明度(background()、alpha())Modifier 可設定元件的背景顏色(如 Box 或 Text 等元件),透過 background() 方法,可以指定顏色(color)、形狀(shape)及不透明度(alpha)。
Text(
    text = "...",
    modifier = Modifier.background(Color.Green),
)
為元件上背景色時,不止可以填單色,還可以用 brush 參數設定漸層色。
val verticalGradientBrush = Brush.verticalGradient(
        colors = listOf(
            Color.Red,
            Color.Yellow,
            Color.White
        )
    )
Box(
    Modifier.size(100.dp).background(brush = verticalGradientBrush)
)
Modifier 也能用於改變元件的不透明度,透過 alpha() 方法,傳入 0 到 1 之間的 Float 數值,0 表示全透明、1 表示不透明。
Text(
    text = "...",
    modifier = Modifier.alpha(0.6f),
)
Modifier 設定邊框(border())Modifier 提供 border() 方法,可用於設定元件的邊框,透過寬度(width)、顏色或筆刷(color 或 brush)及形狀(shape)的設定,就可以幫一段文字增加 2dp 綠色圓角矩形的邊框:
Text(
    text = "...",
    modifier = Modifier
        .padding(10.dp)
        .border(2.dp, SolidColor(Color.Green), RoundedCornerShape(20.dp))
        .padding(10.dp)
)
Modifier 設定裁剪(clip())Compose 也支援用 Modifier 對物件做截剪,比方說在 UI 上有一個使用者大頭照,原本照片是正方形的,若我們想做出圓形的裁剪,就可以用 clip() 來實作:
Image(
    painter = painterResource("..."),
    contentDescription = "...",
    modifier = Modifier.clip(CircleShape)
)
Compose 支援以下這些形狀的裁剪:
RectangleShape
CircleShape
RoundedCornerShape
CutCornerShape
Modifier 設定間距(padding())在寫 UI 時,其實元件與元件之間會有一個隱形的間距,有寫 CSS 經驗的讀者,就知道要設定 Margin 及 Padding。有別於 CSS 這種區分內距及外距的設計,在 Compose 裡只有 padding(),根據它在方法串接的位置發揮不同的效果。
Box(
    modifier = Modifier
        .padding(8.dp)
        .border(
            width = 2.dp,
            color = Color.Red,
            shape = RoundedCornerShape(2.dp)
        )
        .padding(8.dp),
) {
    Box(
        modifier = Modifier.size(width = 100.dp, height = 10.dp)
            .background(Color.Red),
    )
}
在上面的例子裡,在 Box 裡放了另一個 Box,外層的 Box 用 border() 做了一個紅色的圓角矩形外框,在設定邊框的前後加上了 padding(),第一個 padding() 設定的是外距,也就是 Margin,第二個 padding() 則是設定內距,也就是以往經驗裡認知的 Padding。
Modifier 設定尺寸(width()、height()、size())在排版 UI 元件時,很常會需要設定元件尺寸,Modifier 有數個跟尺寸有關的方法可以讓開發者調整元件的寬、高:
width() 可以指定元件的寬度,單位用 dp。height() 可以指定元件的高度,單位用 dp。size(),單位用 dp。不過 size() 方法也可以傳入兩個參數,分別指定寬高。Box(
    modifier = Modifier.size(50.dp)
) {
    // ...
}
Box(
    modifier = Modifier.width(50.dp).height(100.dp)
) {
    // ...
}
Box(
    modifier = Modifier.size(50.dp)
) {
    // ...
}
Box(
    modifier = Modifier.size(width = 50.dp, height = 100.dp)
) {
    // ...
}
除了指定固定的寬高之外,Compose 也支援另外三種自動撐大元件的設定:fillMaxZie() 會將元件上下左右撐到大父元素的大小、fillMaxWidth() 只會撐大寬度到父元素的大小、fillMaxHeight() 則會撐大高度到父元素的大小。
Box(
    modifier = Modifier.fillMaxSize(),
) {
    // ...
}
Box(
    modifier = Modifier.fillMaxWidth(),
) {
    // ...
}
Box(
    modifier = Modifier.fillMaxHeight(),
) {
    // ...
}
Modifier 設定旋轉及縮放(rotate()、scale())Modifier 還可以用於設定元件的旋轉及縮放。rotate() 傳入 0 至 359 的 Float 整數可以讓元件以順時針旋轉,若傳入的是負值,則以逆時針旋轉。scale() 方法則是依傳入的 Float 數值放大元件,放大時可用 scale(scaleX = 2f, scaleY = 3f) 分別指定長寬的放大比例
Image(
    painter = painterResource("kotlin-logo.png"),
    contentDescription = "Kotlin Logo",
    modifier = Modifier.rotate(15f).scale(1.5f)
)
Modifier 設定事件(clickable())Modifier 神奇之處在於還能讓原本沒有事件反應的元件能綁定事件,透過 clickable() 綁定 Event Handler 後 就能讓元件跟使用者互動。
val rotateDegree = remember { mutableStateOf(0f) }
Image(
    painter = painterResource("kotlin-logo.png"),
    contentDescription = "Kotlin Logo",
    modifier = Modifier.clickable {
        rotateDegree.value = rotateDegree.value + 15f
    }.rotate(rotateDegree.value)
)
在上面的例子裡,我們在 Image 綁定了 clickable(),每次點擊圖片時就更改旋轉角度 15 度。透過這麼簡單的設定,這個圖片就可以跟使用者做出滑鼠互動了!