Android开发实战班 - 现代 UI 开发之自定义 Compose 组件
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.Gray val contentColor = if (isSelected) MaterialTheme.colorScheme.onPrimary else Color.White Text( 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 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!
温馨提示:可搜老码小张公号联系导师