D2Modifier

统一挂尺寸、边距、背景、点击;链式调用,顺序有意义。写界面第二高频(第一是状态)。

📌 术语:Modifier。示例里的单行 Modifier.xxx() 表示「作为某组件的 modifier = … 参数」;完整示例包在 @Composable 函数体内。

Modifier 是什么

概念

XML 里尺寸、padding、背景、点击散在属性、style、代码三处。Compose 收成一条链:几乎每个组件都有 modifier: Modifier = Modifier,你往上点方法即可。

一句话:Modifier = 组件「外在表现」的统一入口(占多大、留白、皮、能不能点……)。

和 XML 对照

你想做的事XMLCompose
宽高 / 撑满layout_width/heightsize / fillMaxWidth
内边距paddingpadding
背景background / drawablebackground / clip
点击setOnClickListenerclickable
按比例分空间layout_weightweight(Row/Column 内)

怎么用

@Composable
fun ModifierChainDemo() {
    Text(
        "Hello",
        modifier = Modifier
            .padding(16.dp)
            .background(Color.LightGray)
            .clickable { /* 点击 */ }
    )
}

Modifier 是空起点;每个方法返回新的 Modifier,所以可一直链式追加。不可变、纯函数式拼装。

易错点

  • 把 Modifier 当成「改已经画好的 View」——它是声明链,顺序不同结果不同(见下一节案例)。
  • 组件忘了暴露 modifier 参数——自定义 Composable 应把 modifier 接到根节点,方便外层排版。

★ 常用属性

概念

天天写的那一批:尺寸、padding、背景/边框/裁剪、点击、以及布局作用域里的 weight / align

⚠️ 顺序口诀:先占地盘 → 再画皮 → 后留白 / 交互。常见排法:尺寸 → 背景/边框 → 裁剪 → padding → 对齐/偏移 → 点击。

和 XML 对照 + 怎么用

① 尺寸与占据 ★

// 作为某组件的 modifier 参数,例如 Text("hi", modifier = …)
Modifier.size(48.dp)
Modifier.size(width = 48.dp, height = 24.dp)
Modifier.fillMaxWidth()
Modifier.fillMaxHeight(0.5f)
Modifier.width(120.dp)
Modifier.widthIn(min = 80.dp, max = 200.dp)

fillMax*match_parent;固定 size / width ≈ 定死或 wrap 思路。Row/Column 内按比例分空间用 weight(⑤)。

② padding ★

Modifier.padding(16.dp)
Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
Modifier.padding(start = 8.dp, end = 8.dp, top = 4.dp, bottom = 4.dp)

③ 背景、边框、裁剪 ★

Modifier.background(Color.Blue)
Modifier.background(Color.Red, shape = RoundedCornerShape(8.dp))
Modifier.border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
Modifier.clip(RoundedCornerShape(50))

默认直角。要圆角:background(..., shape) 或配合 clip;阴影用 shadow(○ 节)。

④ 点击 ★

Modifier.clickable { /* 单击 */ }
Modifier.clickable(enabled = false) { /* 禁用 */ }

整行可点时,把 clickable 挂在行容器上(见下方案例),别只给文字加点击。

⑤ weight ★(Row / Column 作用域)

@Composable
fun WeightDemo() {
    Row(modifier = Modifier.fillMaxWidth()) {
        Text("左", modifier = Modifier.weight(1f))
        Text("右", modifier = Modifier.weight(2f))
    }
}

layout_weight只对 Row/Column 的直接子项有效;详见布局 · Row

⑥ align ★(Box 作用域)

@Composable
fun AlignDemo() {
    Box(modifier = Modifier.size(200.dp)) {
        Text("居中", modifier = Modifier.align(Alignment.Center))
        Text("右上", modifier = Modifier.align(Alignment.TopEnd))
    }
}

≈ FrameLayout 的 layout_gravity。详见布局 · Box

易错点

  • weight / align 写在错误作用域 → 编译报错或无效。
  • 圆角背景漏了 shape / clip → 仍是直角色块。
  • 可点区域比视觉小——把 clickable 放在更大的父 Modifier 上,或保证 padding 在 clickable 内侧/外侧符合预期(顺序!)。
▶ 先 padding 再 background,和反过来差在哪

同一组修饰符,顺序一换,红块和留白关系完全不同。下面每侧:代码 + 效果示意

先背景、后 padding
@Composable
fun BgThenPadding() {
    Box(
        modifier = Modifier
            .size(100.dp)
            .background(Color.Red)
            .padding(16.dp)
    )
}
先 padding、后背景
@Composable
fun PaddingThenBg() {
    Box(
        modifier = Modifier
            .padding(16.dp)
            .size(100.dp)
            .background(Color.Red)
    )
}

要点:每个修饰符都基于「前面已经形成的盒子」再加工。调不顺时,先检查链顺序,而不是再加一层 padding 碰运气。

💡 想真机预览:把任一侧函数贴进工程,加 @Preview 即可对照。第三方网页编辑器对 Android Compose 支持不稳定,手册以示意 + Studio Preview 为准。
🔗 @Preview 官方说明

▶ 整行可点的设置项

设置列表一行:左文案、右箭头,整行都能点。XML 常给 item 根布局设 click;Compose 把 clickable + fillMaxWidth + padding 挂在 Row 上。

@Composable
fun SettingsClickRow(
    title: String,
    onClick: () -> Unit
) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = onClick)
            .padding(horizontal = 16.dp, vertical = 14.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Text(
            title,
            modifier = Modifier.weight(1f)
        )
        Text("›")
    }
}

要点:clickable 放在 padding 前,点击热区含边距;若先 padding 再 clickable,热区可能变小(再验证一次顺序口诀)。

💡 复制到 Studio,加 @Preview 点一下即可验证热区。@Preview

○ 偶尔属性

概念

用得到再查,不必一次背完。汇总也会进属性总表

和 XML 对照 / 怎么用

① 变换与层级 ○

modifier.offset(x = 8.dp, y = 8.dp)  // 偏移,不改布局占位
Modifier.rotate(45f)
Modifier.scale(1.2f)
Modifier.alpha(0.5f)
Modifier.zIndex(1f)                   // Box 内叠放顺序

offset ≈ translation,占位仍在原处;真正挤开兄弟用 padding / 布局参数。

② 滚动 / 键盘 ○

@Composable
fun ScrollDemo() {
    Column(
        modifier = Modifier.verticalScroll(rememberScrollState())
    ) {
        // 内容超高时可滚
    }

    Column(
        modifier = Modifier
            .imePadding()
            .verticalScroll(rememberScrollState())
    ) {
        // 键盘弹出时顶起内容
    }
}

长列表优先 Lazy,不要用可滚 Column 硬塞几千项。

③ 阴影 ○

modifier
    .shadow(elevation = 4.dp, shape = RoundedCornerShape(8.dp))
    .clip(RoundedCornerShape(8.dp))
    .background(Color.White)

易错点

  • offset 当「布局间距」→ 重叠/点不到,改用 padding 或 Arrangement。
  • verticalScroll 嵌套 Lazy → 手势冲突,列表章再讲清。

抽成扩展函数

概念

同一串 Modifier 多处复制时,抽成 Modifier 扩展(≈ XML 自定义 style),全项目统一皮肤。

和 XML 对照

XML:style="@style/Card"。Compose:Modifier.cardStyle(),还能在调用处继续链式追加。

怎么用

// 顶层扩展:定义在 @Composable 之外
fun Modifier.cardStyle(): Modifier = this
    .fillMaxWidth()
    .padding(12.dp)
    .clip(RoundedCornerShape(12.dp))
    .background(Color.White)

@Composable
fun CardStyleDemo() {
    Box(modifier = Modifier.cardStyle()) {
        Text("卡片一")
    }
    Box(modifier = Modifier.cardStyle().padding(20.dp)) {
        Text("卡片二") // 链式继续追加
    }
}

易错点

  • 扩展里写死业务点击 / 状态——样式归样式,交互参数仍由调用方传入。
  • 扩展不返回 Modifier(不从 this 起手)→ 调用处无法继续点链。

频率速览

属性作用频率
padding内边距★ 常用
size / fillMaxWidth尺寸 / 撑满★ 常用
background / border / clip外观★ 常用
clickable点击★ 常用
weightRow/Column 分空间★ 常用
alignBox 内定位★ 常用
offset / alpha / shadow变换 / 阴影○ 偶尔
verticalScroll / imePadding滚动 / 键盘○ 偶尔

完整对照进属性总表;下一章开始用这些修饰符喂基础组件

Android Compose 现代开发知识体系 · 主线必读 / 扩展选读。
术语表常驻;组件与属性先看分讲,再查两张总表。案例默认收起。