Composable Function:是什么、函数语法和规则

作者: IT Sectr 发布日期: 2026-06-27 阅读时间: 8 分钟

Composable Function — 是 Jetpack Compose 中用户界面的基本单元,它定义了屏幕的一部分应该如何显示和表现。每个这样的函数都用 @Composable 注解标记,并在特殊上下文中执行,使 Compose 能够跟踪依赖关系并在数据变化时自动重建 UI。根据 Google Android Developers, 2026,正确构建 Composable 函数直接影响应用程序的性能和重组效率。

要点

  • Composable Function — 带有 @Composable 注解的 Kotlin 函数,构建 UI 树
  • 参数 应该是不可变的,可变数据通过 state 传递
  • 调用 只能从其他 Composable 函数的上下文中进行
  • 执行顺序 无法保证 — 每个函数应该独立
  • Modifier 建议作为参数传递以进行自定义

什么是 Jetpack Compose 中的 Composable Function

Composable Function — 是 Kotlin 语言中使用 @Composable 注解标记的函数,以声明方式描述用户界面的一部分。开发人员无需通过 Java 代码或 XML 标记创建和配置 View 对象,只需编写 UI 在每个数据状态下应如何显示。

Composable 函数与传统的 Android View 系统之间的主要区别在于更新模型。在经典方法中,开发人员手动调用 findViewById、通过 setText 更改文本、通过 setVisibility 管理可见性。Composable Function 摆脱了这种繁琐工作:当数据变化时,系统自行确定哪些函数需要重新启动,并只执行这些函数。

Kotlin 编译器在处理 @Composable 注解时会生成额外代码,将函数集成到组合机制中。这段代码包括对插槽(存储当前 UI 树中每个 Composable 函数状态和参数的特殊存储单元)的读写操作。得益于这种集成,Compose 知道哪些函数依赖于哪些数据。

声明 Composable 函数的语法

Composable 函数 的语法非常简洁:只需在 fun 关键字前添加 @Composable 即可。函数可以接受任何参数,在其主体中包含其他 Composable 调用,并使用 Kotlin 构造(条件、循环、when 表达式)来有条件地显示 UI。

kotlin
@Composable
fun ProductItem(
    product: Product,
    modifier: Modifier = Modifier,
    onAddToCart: () -> Unit
) {
    Card(modifier = modifier.padding(8.dp)) {
        Row(modifier = Modifier.fillMaxWidth().padding(12.dp),
            verticalAlignment = Alignment.CenterVertically) {
            Column(modifier = Modifier.weight(1f)) {
                Text(text = product.name, style = MaterialTheme.typography.titleMedium)
                Text(text = "${product.price}", color = MaterialTheme.colorScheme.primary)
            }
            Button(onClick = onAddToCart) {
                Text("添加到购物车")
            }
        }
    }
}

在此示例中,ProductItem Composable 函数接收一个 Product 对象、一个修饰符和一个回调。所有三个参数都是不可变的,这保证了重组时的可预测行为。修饰符作为具有默认值的参数传递 — 这是标准做法,允许调用方自定义边距和尺寸。

Composable 函数中的组件和修饰符

Composable 函数 内部,使用 Material Design 内置组件(Text、Button、Card、TextField)或基本原语(Canvas、Layout)。每个组件都接受参数来配置外观和行为,并通过 modifier 参数接受一个或多个修饰符。

修饰符(Modifier)—— 是一系列函数,用于改变组件的大小、位置、事件处理和外观。修饰符在链中的顺序 很重要:clickable.semantics 与 semantics.clickable 的工作方式不同,而 padding.background 会着色包括 padding 在内的背景区域,这在设计时至关重要。

在 Composable 函数内部,可以使用 if 和 when 条件来有条件地显示 UI 部分,以及使用 for 循环来显示动态列表。所有这些构造都可以自然工作,因为 Kotlin 是一种完整的编程语言。但重要的是要记住:如果条件或循环包含 Composable 函数调用,它们也会参与重组。

kotlin
@Composable
fun ProductList(
    products: List<Product>,
    modifier: Modifier = Modifier
) {
    LazyColumn(modifier = modifier) {
        items(products, key = { it.id }) { product ->
            ProductItem(
                product = product,
                onAddToCart = { /* add to cart */ }
            )
        }
    }
}

针对实际屏幕的 Composable 函数示例

让我们看一个使用多个 Composable 函数 的产品搜索屏幕示例。这里展示了典型的模式:带状态的输入字段、列表过滤、空结果和加载处理。

kotlin
data class Product(
    val id: String,
    val name: String,
    val price: Double,
    val category: String
)

@Composable
fun SearchScreen() {
    var query by remember { mutableStateOf("") }
    val products = remember(query) { getFilteredProducts(query) }

    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        OutlinedTextField(
            value = query,
            onValueChange = { query = it },
            label = { Text("搜索产品") },
            modifier = Modifier.fillMaxWidth()
        )

        Spacer(modifier = Modifier.height(16.dp))

        when (products) {
            is Loading -> CircularProgressIndicator()
            is Empty -> Text("未找到结果")
            is Result -> LazyColumn {
                items(products.items, key = { it.id }) { product ->
                    ProductItem(product = product, onAddToCart = {})
                }
            }
        }
    }
}

此示例同时展示了多个惯用法:remember 用于保存搜索查询状态、remember(query) 用于带键过滤、when 用于三种 UI 状态以及 LazyColumn 用于高效显示列表。每个这些惯用法都是在开发 Compose 应用程序中获得的实际经验结果。

参数和 Slot API

Composable 函数 与普通 Kotlin 函数一样接受参数,但有一个重要区别:参数可以是另一个 Composable 函数,通过带有 @Composable 注解的 lambda 传递。这种机制称为 Slot API,是创建可重用容器的主要模式。

Slot API 解决了在传统 View 系统中通过 ViewGroup 和编程方式添加子 View 来解决的问题。Compose 不使用 addView 方法,而是使用 content lambda — 最后一个参数类型为 @Composable () -> Unit。调用方将任何 UI 传递给此 lambda,而容器本身仅确定其位置。

Composable 函数的参数可以有默认值,这简化了它们在不同上下文中的使用。建议 只将那些函数无法在没有它们的情况下执行其任务的参数设为必填,其他参数则配备合理的默认值。

参数类型示例
必填任何类型name: String
可选带有默认值modifier: Modifier = Modifier
Content@Composable () -> Unitcontent: @Composable () -> Unit
回调不带 @Composable 的 lambdaonClick: () -> Unit

Kotlin 中 Composable 函数的惯用法

在 Compose 社区中形成了几个成熟的惯用法,使 Composable 函数 更具可读性和可预测性。第一个 — State Hoisting:状态被提升到更高层级,Composable 函数通过参数接收状态。这使得函数变得纯函数,并在不同上下文中可重用。

第二个惯用法 — 事件驱动 参数。不将 ViewModel 或 useCase 传递给 Composable 函数,只传递特定的回调:onSave、onDelete、onNavigateToDetail。这降低了耦合性并简化了测试 — 测试 ProductItem 不需要 ViewModel,只需要 lambda 存根。

第三个惯用法 — CompositionLocal 用于通过组合树传递公共数据。主题、屏幕密度、当前路由 — 所有这些都通过 CompositionLocal 传递,避免了通过几十个 Composable 函数的参数链。但是不应滥用 CompositionLocal:显式参数总是优于隐式依赖。

kotlin
// State Hoisting: 状态提升到父函数
@Composable
fun CounterDisplay(
    count: Int,
    onIncrement: () -> Unit
) {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text(text = "计数器: $count", style = MaterialTheme.typography.headlineLarge)
        Button(onClick = onIncrement) {
            Text("+1")
        }
    }
}

// 使用 State Hoisting
@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }
    CounterDisplay(
        count = count,
        onIncrement = { count++ }
    )
}

常见问题

可以在 Composable 函数中使用 return 吗?

可以,return 是允许的,但要小心。Compose 在单个函数级别优化重组,提前 return 可能会破坏这种优化。最好在函数体内使用 if 或 when 条件运算符。

Unit-return 与 Java 中的 void 有何不同?

在 Kotlin 中,Unit 是一个单例对象,而不是空类型。Composable 函数返回 Unit,这技术上说它们返回的是 Unit 对象本身。但在实践中这并不重要 — 返回值会被组合系统忽略。

可以将 mutableListOf 传递给 Composable 函数吗?

传递 可变集合 是可能的,但这是不好的做法。如果集合发生变化,Compose 不会知道,因为对对象的引用保持不变。对于可追踪的更改,请使用不可变列表或 mutableStateListOf。

如何调试 Composable 函数?

使用 Android Studio 的 Layout Inspector 进行调试,它会显示当前的 Composable 函数树、参数值和重组原因。常规的 Kotlin 调试器也可以工作 — Composable 函数内部的断点在每次重组时都会正确触发。

Composable 函数是否需要指定 return type?

Composable 函数 总是返回 Unit,因此无需指定 return type。尝试返回其他类型将导致编译错误,因为 @Composable 注解与不是 Unit 的返回类型不兼容。

总结

  • Composable Function — 用 @Composable 标记的声明式 UI 构建块
  • 参数 对于可预测的重组应为不可变
  • 修饰符 和 Slot API 提供了灵活性和无需继承的可重用性
  • State Hoisting — 将状态上提以实现纯净性和可测试性
  • 事件驱动 回调减少与 ViewModel 和业务逻辑的耦合
  • CompositionLocal 用于公共数据,但显式参数更优
  • 惯用法 Compose 使代码可预测、可测试且高性能

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读