Android ComposeUI详解

515 阅读6分钟

Android Compose UI 详解:组件、修饰符与布局注意事项

Jetpack Compose 是 Android 官方的声明式 UI 框架,基于 Kotlin 构建,通过可组合函数(@Composable)描述 UI。以下是其核心组件、修饰符用法及布局注意事项的详细说明:

一、核心 UI 组件(Composables)

1. 基础组件

用于展示文本、图片、按钮等基础元素。

组件作用常用参数示例
Text显示文本text(内容)、fontSizecolorfontWeightmaxLineskotlin Text( text = "Hello Compose", fontSize = 18.sp, color = Color.Blue, fontWeight = FontWeight.Bold )
Image显示图片painter(资源)、contentDescription(无障碍描述)、contentScale(缩放模式)kotlin Image( painter = painterResource(id = R.drawable.ic_logo), contentDescription = "App Logo", contentScale = ContentScale.Fit )
Button可点击按钮onClick(点击事件)、modifiercolors(颜色)、shape(形状)kotlin Button( onClick = { /* 点击逻辑 */ }, colors = ButtonDefaults.buttonColors(containerColor = Color.Green) ) { Text("Click Me") }
Icon显示系统图标imageVector(矢量图标)、contentDescriptiontint(色调)kotlin Icon( imageVector = Icons.Default.Favorite, contentDescription = "Like", tint = Color.Red )
TextField文本输入框value(输入值)、onValueChange(值变化回调)、label(标签)、placeholder(占位符)kotlin var text by remember { mutableStateOf("") } TextField( value = text, onValueChange = { text = it }, label = { Text("Enter text") } )

2. 布局容器

用于组织多个组件的排列方式,类似传统布局的 LinearLayoutFrameLayout

容器作用关键参数示例
Column垂直排列子组件horizontalAlignment(水平对齐)、verticalArrangement(垂直间距)、modifierkotlin Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text("First") Text("Second") }
Row水平排列子组件verticalAlignment(垂直对齐)、horizontalArrangement(水平间距)kotlin Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { Text("Left") Text("Right") }
Box层叠排列子组件(类似 FrameLayoutcontentAlignment(子组件对齐方式)kotlin Box(contentAlignment = Alignment.Center) { Image(...) // 底层 Text("Overlay") // 叠加在图片上 }
LazyColumn高效滚动列表(仅渲染可见项)content(列表项)、modifierkotlin LazyColumn { items(100) { index -> Text("Item $index") } }
LazyRow水平滚动列表LazyColumn,方向为水平kotlin LazyRow { items(50) { Text("Item $it") } }
ConstraintLayout复杂约束布局通过 createRefs() 定义约束关系kotlin ConstraintLayout { val (text, button) = createRefs() Text("Hello", modifier = Modifier.constrainAs(text) { top.linkTo(parent.top) }) Button( modifier = Modifier.constrainAs(button) { top.linkTo(text.bottom) } ) { Text("Button") } }

3. 交互组件

用于响应用户操作(点击、滑动等)。

组件作用示例
Clickable使任意组件可点击kotlin Text("Click me") .clickable { /* 点击逻辑 */ }
Checkbox复选框kotlin var checked by remember { mutableStateOf(false) } Checkbox( checked = checked, onCheckedChange = { checked = it } )
RadioButton单选按钮(需配合 RadioGroup 逻辑)kotlin var selectedOption by remember { mutableStateOf("A") } RadioButton( selected = selectedOption == "A", onClick = { selectedOption = "A" } )
Switch开关控件kotlin var enabled by remember { mutableStateOf(false) } Switch( checked = enabled, onCheckedChange = { enabled = it } )
Slider滑动条(选择数值)kotlin var progress by remember { mutableStateOf(0.5f) } Slider( value = progress, onValueChange = { progress = it } )

4. 容器组件

用于分组或装饰子组件。

组件作用示例
Card带阴影和圆角的卡片容器kotlin Card( elevation = 4.dp, shape = RoundedCornerShape(8.dp), modifier = Modifier.padding(8.dp) ) { Column { Text("Card Title") } }
Surface基础容器,可设置背景、边框等kotlin Surface( color = Color.LightGray, modifier = Modifier.padding(8.dp) ) { Text("Content") }
ScrollState + Scrollable自定义滚动容器(替代 ScrollViewkotlin val scrollState = rememberScrollState() Column( modifier = Modifier.verticalScroll(scrollState) ) { // 长内容 }

二、修饰符(Modifier)详解

修饰符(Modifier)用于修改组件的外观和行为,通过链式调用组合多个效果。常用修饰符分类如下:

1. 尺寸与布局

控制组件的大小、位置和约束。

修饰符作用示例
size(width, height)固定宽高Modifier.size(100.dp, 50.dp)
size(size)宽高相等(正方形)Modifier.size(50.dp)
width(width) / height(height)单独设置宽/高Modifier.width(200.dp)
fillMaxSize()占满父容器的宽和高Modifier.fillMaxSize()
fillMaxWidth() / fillMaxHeight()占满父容器的宽/高Modifier.fillMaxWidth(0.8f)(占 80% 宽度)
wrapContentSize()尺寸适应内容Modifier.wrapContentSize()
minimumSize() / maximumSize()最小/最大尺寸限制Modifier.minimumSize(50.dp)

2. 间距与边距

控制组件的内边距和外边距。

修饰符作用示例
padding(all)四周统一内边距Modifier.padding(16.dp)
padding(horizontal, vertical)水平和垂直内边距Modifier.padding(8.dp, 16.dp)
padding(start, top, end, bottom)单独设置四边内边距Modifier.padding(4.dp, 8.dp, 4.dp, 8.dp)
padding(insets)基于系统Insets(如状态栏)的内边距Modifier.padding(WindowInsets.statusBars.asPaddingValues())
margin()外边距(同 padding,但作用于组件外部)Modifier.margin(8.dp)

3. 背景与边框

设置组件的背景色、形状和边框。

修饰符作用示例
background(color, shape)背景色和形状Modifier.background(Color.Blue, RoundedCornerShape(8.dp))
border(width, color, shape)边框Modifier.border(2.dp, Color.Red, CircleShape)
clip(shape)裁剪组件为指定形状Modifier.clip(RoundedCornerShape(4.dp))

4. 交互与行为

控制组件的交互能力(点击、焦点等)。

修饰符作用示例
clickable(onClick, enabled)使组件可点击Modifier.clickable { /* 逻辑 */ }.enabled(false)(禁用点击)
focusable()允许组件获取焦点(用于键盘导航)Modifier.focusable()
scrollable(state, orientation)使组件可滚动Modifier.scrollable(rememberScrollState(), Orientation.Vertical)
draggable(state)使组件可拖拽kotlin val offset = remember { mutableStateOf(Offset.Zero) } Box( modifier = Modifier .offset { IntOffset(offset.value.x.roundToInt(), offset.value.y.roundToInt()) .draggable( onDrag = { delta -> offset.value += delta } ) } )

5. 其他常用修饰符

修饰符作用示例
align(alignment)在父容器中对齐(仅在 Box/Column/Row 中生效)Modifier.align(Alignment.CenterEnd)
weight(weight)Column/Row 中分配剩余空间Modifier.weight(1f)(占 1 份权重)
alpha(alpha)透明度(0f 全透明,1f 不透明)Modifier.alpha(0.5f)
rotation(degrees)旋转组件Modifier.rotation(45f)
scale(scaleX, scaleY)缩放组件Modifier.scale(1.5f)
testTag(tag)用于 UI 测试的标记Modifier.testTag("submit_button")

三、布局 UI 时的注意事项

1. 性能优化

  • 避免过度重组

    • 将复杂 UI 拆分为小型可组合函数,减少状态变化时的重组范围。
    • remember 缓存计算结果或对象,避免重复创建:
      // 缓存点击事件(避免每次重组创建新 lambda)
      val onButtonClick = remember { { /* 逻辑 */ } }
      Button(onClick = onButtonClick) { ... }
      
    • 避免在 modifier 中创建匿名对象(如 Modifier.clickable { ... } 中的 lambda 会被频繁重建,复杂逻辑需用 remember 缓存)。
  • 列表优化

    • 长列表必须使用 LazyColumn/LazyRow,而非 Column+Scrollable(前者仅渲染可见项,后者会加载所有项)。
    • LazyColumnitems 提供稳定的 key,避免不必要的项重建:
      LazyColumn {
          items(users, key = { it.id }) { user -> // 用唯一 ID 作为 key
              UserItem(user)
          }
      }
      
  • 图片优化

    • 网络图片使用 Coil 库(rememberAsyncImagePainter),支持缓存和占位符:
      Image(
          painter = rememberAsyncImagePainter(
              model = "https://example.com/image.jpg",
              placeholder = painterResource(id = R.drawable.placeholder)
          ),
          contentDescription = null
      )
      
    • 本地图片避免使用过大分辨率,通过 contentScale 适配容器尺寸。

2. 布局结构合理性

  • 减少嵌套层级

    • 避免多层 Box/Column 嵌套(如 Box { Box { Column { ... } } }),会增加布局计算耗时。
    • 优先使用 ConstraintLayout 实现复杂布局,减少嵌套。
  • 权重分配谨慎使用

    • weight 修饰符会强制子组件占据剩余空间,过度使用可能导致布局计算复杂。
    • LazyColumn 中避免使用 weight(会破坏懒加载机制)。
  • 处理不同屏幕尺寸

    • 使用 dp 作为尺寸单位(自动适配不同密度屏幕)。
    • 避免硬编码尺寸,优先用 fillMaxWidth/wrapContentSize 自适应。
    • 对大屏幕(如平板),可通过 WindowSizeClass 动态调整布局:
      val windowSizeClass = calculateWindowSizeClass(context)
      if (windowSizeClass.widthSizeClass > WindowWidthSizeClass.Compact) {
          // 平板:水平布局
          Row { ... }
      } else {
          // 手机:垂直布局
          Column { ... }
      }
      

3. 无障碍支持

  • 为所有交互组件和图片添加 contentDescription,方便屏幕阅读器识别:
    Image(
        painter = ...,
        contentDescription = "用户头像" // 必须提供,除非是纯装饰性图片(设为 null 并添加 .semantics { isDecoration = true })
    )
    
  • 使用 Semantics 修饰符增强无障碍信息:
    Button(onClick = {}) {
        Text("提交")
    }.semantics {
        contentDescription = "确认表单提交按钮"
    }
    

4. 主题与样式统一

  • 所有组件样式(颜色、字体、形状)应基于 MaterialTheme,避免硬编码:
    // 正确:使用主题颜色
    Text(
        "Title",
        color = MaterialTheme.colorScheme.primary,
        style = MaterialTheme.typography.headlineSmall
    )
    
    // 错误:硬编码颜色
    Text("Title", color = Color(0xFF6200EE)) // 难以统一修改
    
  • 通过 CompositionLocalProvider 自定义主题扩展(如自定义间距、圆角)。

5. 与传统 View 的兼容

  • 在 Compose 中嵌入传统 View 时,使用 AndroidView 并注意生命周期管理:
    AndroidView(
        factory = { context ->
            TextView(context).apply {
                text = "传统 TextView"
            }
        },
        update = { textView ->
            // 当依赖的状态变化时更新 View
            textView.text = newText
        }
    )
    
  • 避免频繁在 Compose 和传统 View 间切换,可能导致性能问题。

总结

Compose 通过组件和修饰符的组合实现灵活的 UI 开发,核心是声明式思想和状态驱动。布局时需关注性能(重组、列表优化)、结构合理性(减少嵌套、适配屏幕)、无障碍支持和样式统一。熟练掌握这些细节可显著提升开发效率和应用质量。