Jetpack Compose 不仅提供了丰富的内置组件,还允许开发者根据项目需求创建自定义组件。自定义 Compose 组件可以提高代码复用性、简化 UI 逻辑,并使应用界面更加一致和模块化。本章节将介绍如何创建自定义 Compose 组件,包括组件的创建、样式定制、状态管理以及在项目中的应用。
为什么需要自定义 Compose 组件
-
代码复用:
- 通过创建自定义组件,可以将常用的 UI 逻辑封装起来,避免重复代码,提高代码复用性。
-
简化 UI 逻辑:
- 将复杂的 UI 逻辑封装到自定义组件中,可以简化调用代码,使代码更简洁易懂。
-
一致性:
- 自定义组件可以保证应用界面的一致性,例如统一的按钮样式、输入框样式等。
-
模块化:
- 自定义组件可以将 UI 拆分成更小的模块,便于维护和测试。
创建自定义 Compose 组件
创建自定义 Compose 组件非常简单,只需定义一个带有 @Composable
注解的函数即可。以下是一个简单的自定义按钮组件示例:
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp@Composable
fun MyButton(text: String,onClick: () -> Unit,modifier: Modifier = Modifier,backgroundColor: Color = MaterialTheme.colorScheme.primary,contentColor: Color = MaterialTheme.colorScheme.onPrimary
) {Text(text = text,modifier = modifier.clip(RoundedCornerShape(8.dp)).background(backgroundColor).clickable { onClick() }.padding(vertical = 12.dp, horizontal = 16.dp),color = contentColor,style = MaterialTheme.typography.labelLarge)
}
-
参数说明:
text
: 按钮显示的文本。onClick
: 按钮点击事件回调。modifier
: 修饰符,用于自定义按钮的布局和样式。backgroundColor
: 按钮背景颜色,默认为主题主色。contentColor
: 按钮文本颜色,默认为主题主色文本颜色。
-
使用自定义按钮:
MyButton(text = "Click Me",onClick = { /* 处理点击事件 */ },modifier = Modifier.align(Alignment.Center) )
样式定制
自定义 Compose 组件可以通过参数传递样式,例如颜色、字体、形状等,从而实现样式的定制。
-
颜色定制:
- 可以通过参数传递不同的颜色值来定制组件的颜色。
MyButton(text = "Red Button",onClick = { /* 处理点击事件 */ },backgroundColor = Color.Red,contentColor = Color.White )
- 可以通过参数传递不同的颜色值来定制组件的颜色。
-
字体和排版:
- 可以通过
MaterialTheme.typography
来定制组件的字体和排版。MyButton(text = "Large Button",onClick = { /* 处理点击事件 */ },modifier = Modifier.padding(16.dp),style = MaterialTheme.typography.headlineMedium )
- 可以通过
-
形状定制:
- 可以通过
clip()
和RoundedCornerShape
等函数来定制组件的形状。MyButton(text = "Rounded Button",onClick = { /* 处理点击事件 */ },modifier = Modifier.clip(RoundedCornerShape(16.dp)) )
- 可以通过
状态管理
自定义 Compose 组件可以管理自己的状态,例如按钮的选中状态、输入框的内容等。
-
按钮选中状态:
@Composable fun ToggleButton(text: String,isSelected: Boolean,onToggle: (Boolean) -> Unit,modifier: Modifier = Modifier ) {val backgroundColor = if (isSelected) MaterialTheme.colorScheme.primary else Color.Grayval contentColor = if (isSelected) MaterialTheme.colorScheme.onPrimary else Color.WhiteText(text = text,modifier = modifier.clip(RoundedCornerShape(8.dp)).background(backgroundColor).clickable { onToggle(!isSelected) }.padding(vertical = 12.dp, horizontal = 16.dp),color = contentColor,style = MaterialTheme.typography.labelLarge) }// 使用 ToggleButton var isButtonSelected by remember { mutableStateOf(false) }ToggleButton(text = "Toggle Me",isSelected = isButtonSelected,onToggle = { isButtonSelected = it } )
-
输入框内容状态:
@Composable fun MyTextField(value: String,onValueChange: (String) -> Unit,modifier: Modifier = Modifier,label: String = "" ) {TextField(value = value,onValueChange = onValueChange,label = { Text(text = label) },modifier = modifier,colors = TextFieldDefaults.textFieldColors(containerColor = MaterialTheme.colorScheme.secondaryContainer,textColor = MaterialTheme.colorScheme.onSecondaryContainer,placeholderColor = MaterialTheme.colorScheme.onSecondaryContainer.copy(alpha = 0.5f))) }// 使用 MyTextField var text by remember { mutableStateOf("") }MyTextField(value = text,onValueChange = { text = it },label = "Enter text" )
实战案例
-
案例一:自定义导航栏组件
- 创建一个自定义导航栏组件,包含多个导航项。
- 使用
Row
和Button
组件实现导航栏布局。 - 通过参数传递导航项列表和点击事件回调。
@Composable fun MyNavigationBar(items: List<String>,onItemClick: (String) -> Unit,modifier: Modifier = Modifier ) {Row(modifier = modifier) {items.forEach { item ->MyButton(text = item,onClick = { onItemClick(item) },modifier = Modifier.weight(1f))}} }// 使用 MyNavigationBar val navigationItems = listOf("Home", "Settings", "Profile") var selectedItem by remember { mutableStateOf("Home") }MyNavigationBar(items = navigationItems,onItemClick = { selectedItem = it } )
-
自定义卡片组件
- 创建一个自定义卡片组件,包含标题、内容和按钮。
- 使用
Card
,Column
,Text
,Button
等组件实现卡片布局。 - 通过参数传递标题、内容和按钮文本。
@Composable fun MyCard(title: String,content: String,buttonText: String,onButtonClick: () -> Unit,modifier: Modifier = Modifier ) {Card(modifier = modifier,elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),shape = RoundedCornerShape(8.dp)) {Column(modifier = Modifier.padding(16.dp)) {Text(text = title,style = MaterialTheme.typography.titleMedium,modifier = Modifier.padding(bottom = 8.dp))Text(text = content,style = MaterialTheme.typography.bodyMedium,modifier = Modifier.padding(bottom = 12.dp))MyButton(text = buttonText,onClick = onButtonClick)}} }// 使用 MyCard MyCard(title = "Welcome",content = "Thank you for using our app!",buttonText = "OK",onButtonClick = { /* 处理按钮点击事件 */ } )
课后作业
-
任务一:创建一个自定义按钮组件
- 定义一个自定义按钮组件
MyButton
,包含文本、点击事件、颜色、字体等参数。 - 使用
Modifier
和 Compose 布局组件实现按钮布局。 - 在应用中调用
MyButton
组件,并传递不同的参数。
- 定义一个自定义按钮组件
-
任务二:创建一个自定义卡片组件
- 定义一个自定义卡片组件
MyCard
,包含标题、内容、按钮文本和点击事件等参数。 - 使用
Card
,Column
,Text
,Button
等组件实现卡片布局。 - 在应用中调用
MyCard
组件,并传递不同的参数。
- 定义一个自定义卡片组件
-
任务三:实现一个自定义导航栏组件
- 定义一个自定义导航栏组件
MyNavigationBar
,包含导航项列表和点击事件回调。 - 使用
Row
和MyButton
组件实现导航栏布局。 - 在应用中调用
MyNavigationBar
组件,并传递导航项列表和点击事件回调。
- 定义一个自定义导航栏组件
通过本章节的学习,学员将能够掌握创建自定义 Compose 组件的方法,包括组件的创建、样式定制、状态管理以及在项目中的应用,从而提高代码复用性、简化 UI 逻辑,并使应用界面更加一致和模块化。
作者简介
前腾讯电子签的前端负责人,现 whentimes tech CTO,专注于前端技术的大咖一枚!一路走来,从小屏到大屏,从 Web 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!
温馨提示:可搜老码小张公号联系导师