版本号
CmComposeUI 是一个基于 Kotlin Multiplatform Compose 的 UI 组件库,提供丰富的通用组件,支持 Android 和 iOS 双平台。
引入使用
在项目根目录 settings.gradle.kts 添加 JitPack 仓库:
dependencyResolutionManagement {
repositories {
maven { url = uri("https://jitpack.io") }
}
}
在共享代码模块
composeApp/src/commonMain/kotlin 的 build.gradle.kts 中添加依赖:
重要说明:这是一个多模块项目,JitPack 需要指定
composeApp子模块。
kotlin {
sourceSets {
commonMain {
dependencies {
implementation("com.github.Peakmain.CmComposeUI:composeApp:latest-version")
}
}
}
}
或者简写方式:
dependencies {
commonMainImplementation("com.github.Peakmain.CmComposeUI:composeApp:latest-version")
}
项目结构
composeApp/
├── src/
│ ├── commonMain/
│ │ └── kotlin/com/peakmain/cmp_compose/
│ │ ├── basic/ # 基础常量
│ │ │ ├── BasicColor.kt # 颜色常量
│ │ │ ├── BasicFont.kt # 字体大小常量
│ │ │ └── BasicSize.kt # 尺寸常量
│ │ ├── space/ # 间距
│ │ │ └── PkSpacer.kt # 间距组件
│ │ ├── theme/ # 主题
│ │ ├── ui/ # UI 组件
│ │ │ ├── banner/ # 轮播
│ │ │ │ └── PkBanner.kt # 轮播组件
│ │ │ ├── button/ # 按钮
│ │ │ │ ├── PkButton.kt # 按钮组件
│ │ │ │ └── PkButtonDefault.kt # 默认配置
│ │ │ ├── cell/ # 单元格
│ │ │ │ └── PkCell.kt # 单元格组件
│ │ │ ├── divier/ # 分割线
│ │ │ │ ├── PkDivider.kt # 分割线组件
│ │ │ │ ├── PkDashDivider.kt
│ │ │ │ └── PkFullDivider.kt
│ │ │ ├── flow/ # 流式布局
│ │ │ │ └── PkFlowRow.kt
│ │ │ ├── grid/ # 瀑布流
│ │ │ │ └── PkStaggeredVerticalGrid.kt
│ │ │ ├── image/ # 图片
│ │ │ │ └── PkImageView.kt
│ │ │ ├── progress/ # 进度条
│ │ │ │ └── RoundedLinearProgressIndicator.kt
│ │ │ ├── text/ # 文本
│ │ │ │ └── PkHighlightText.kt
│ │ │ └── title/ # 标题/导航栏
│ │ │ ├── PkNavBar.kt # 顶部导航栏
│ │ │ └── PkTitle.kt # 标题文本
│ │ └── utils/ # 工具类
│ ├── androidMain/ # Android 平台代码
│ └── iosMain/ # iOS 平台代码
└── ...
3. 基础组件
3.1. 顶部应用栏(AppBar)组件
3.1.1. 介绍
TopAppBarCenter 是一个高度定制的顶部应用栏(App Bar)组件,基于 Jetpack Compose 实现。主要特性包括:
- 标题居中显示,支持自定义标题内容
- 可配置左侧导航图标(如返回按钮)和右侧操作图标组
- 支持沉浸式状态栏(透明状态栏,内容延伸到状态栏下方)
- 动态控制状态栏图标颜色(深色或浅色)
- 无缝集成
Scaffold,可直接作为其TopBar参数使用
3.1.2. 参数
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
title | @Composable () -> Unit | 是 | 无 | 标题内容(支持任意 Composable 内容,默认居中显示) |
modifier | Modifier | 否 | Modifier | 布局修饰符,会与组件内部修饰符合并 |
navigationIcon | @Composable (() -> Unit)? | 否 | null | 左侧导航图标(如返回按钮),若为 null则不显示 |
backgroundColor | Color | 否 | MaterialTheme.colors.primarySurface | 应用栏背景颜色 |
actions | @Composable RowScope.() -> Unit | 否 | {} | 右侧操作图标组(可包含多个图标按钮) |
isImmersive | Boolean | 否 | false | 是否启用沉浸式状态栏(透明状态栏,内容向上延伸) |
darkIcons | Boolean | 否 | false | 状态栏图标颜色是否为深色(true为黑色,false为白色),仅在 isImmersive=true时生效 |
content | @Composable (PaddingValues) -> Unit | 是 | 无 | 页面主体内容(通过 Scaffold插入到应用栏下方) |
3.1.3. 示例代码
@Composable
fun HomeFragment() {
TopAppBarCenter(
title = {
Text(text = "首页", color = Color.White)
},
isImmersive = true,
modifier = Modifier.background(Brush.linearGradient(listOf(Color_149EE7, Color_2DCDF5)))
) {
Column(
modifier = Modifier
.padding(BasicSpace.space_18)
.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(BasicSpace.space_18),
horizontalAlignment = Alignment.CenterHorizontally
) {
PkCell(text = "标题组件", modifier = Modifier.clickable {
}, type = PkTitleType.TitleBold1())
PkCell(text = "单元格组件", modifier = Modifier.clickable {
}, type = PkTitleType.TitleBold1())
PkCell(text = "按钮组件", modifier = Modifier.clickable {
}, type = PkTitleType.TitleBold1())
PkCell(text = "图片组件", modifier = Modifier.clickable {
}, type = PkTitleType.TitleBold1())
}
}
}
3.2. 标题组件
3.2.1. 介绍
- 用于快速实现设计规范中的标题和内文样式。通过预定义的
PkTitleType密封类(包含大标题、标题、小标题、内文等多种样式),开发者可以快速选择字体大小、字重等属性,保证 UI 一致性。 - 组件支持自定义颜色、对齐方式、溢出处理等常见文本属性,同时保留与原生
Text组件的兼容性
3.2.2. 参数说明
| 参数名 | 参数类型 | 是否必填 | 说明 |
|---|---|---|---|
text | String | 是 | 需要显示的文本内容 |
type | PkTitleType | 否 | 标题类型(默认为 BigTitle1),支持选择预定义的标题样式(如大标题、小标题、内文等) |
modifier | Modifier | 否 | 布局修饰符(默认 Modifier),用于调整文本的布局、尺寸、间距等 |
color | Color | 否 | 文本颜色(默认 0xFF333333) |
fontStyle | FontStyle? | 否 | 字体风格(如斜体 FontStyle.Italic),默认 null表示不设置 |
textAlign | TextAlign? | 否 | 文本对齐方式(如居中 TextAlign.Center),默认 null表示继承父布局对齐 |
overflow | TextOverflow | 否 | 文本溢出处理方式(默认 TextOverflow.Clip),支持 Ellipsis等效果 |
maxLines | Int | 否 | 文本最大行数(默认无限制 Int.MAX_VALUE) |
style | TextStyle | 否 | 自定义文本样式(默认 LocalTextStyle.current),可覆盖 type中的部分属性 |
3.2.3. PkTitleType 类型说明
PkTitleType 是一个密封类,定义了以下预置样式:
| 类型名称 | 字体大小 | 字重 | 说明 |
|---|---|---|---|
BigTitle1 | 24.sp | W500 | 大标题1(默认类型) |
BigTitle2 | 22.sp | W500 | 大标题2 |
BigTitle3 | 18.sp | W500 | 大标题3 |
TitleBold1 | 16.sp | W500 | 标题1(加粗) |
TitleNormal1 | 16.sp | W400 | 标题1(常规) |
TitleBold2 | 15.sp | W500 | 标题2(加粗) |
TitleNormal2 | 15.sp | W400 | 标题2(常规) |
SmallTitleBold | 14.sp | W500 | 小标题(加粗) |
SmallTitleNormal | 14.sp | W400 | 小标题(常规) |
TextBold1 | 12.sp | W500 | 内文1(加粗) |
TextNormal1 | 12.sp | W400 | 内文1(常规) |
TextBold2 | 11.sp | W500 | 内文2(加粗) |
TextNormal2 | 11.sp | W400 | 内文2(常规) |
3.2.4. 示例代码
Column(verticalArrangement = Arrangement.spacedBy(8.dp), horizontalAlignment = Alignment.CenterHorizontally) {
PkTitle("大标题1", PkTitleType.BigTitle1())
PkTitle("大标题2", PkTitleType.BigTitle2())
PkTitle("大标题3", PkTitleType.BigTitle3())
PkDivider(modifier = Modifier.padding(vertical = 10.dp), isHorizontal = true)
PkTitle("标题1加粗", PkTitleType.TitleBold1())
PkTitle("标题1常规", PkTitleType.TitleNormal1())
PkTitle("标题2加粗", PkTitleType.TitleBold2())
PkTitle("标题2常规", PkTitleType.TitleNormal2())
PkDivider(modifier = Modifier.padding(vertical = 10.dp), isHorizontal = true)
PkTitle("小标题加粗", PkTitleType.SmallTitleBold())
PkTitle("小标题常规", PkTitleType.SmallTitleNormal())
PkDivider(modifier = Modifier.padding(vertical = 10.dp), isHorizontal = true)
PkTitle("内文1加粗", PkTitleType.TextBold1())
PkTitle("内文1正常", PkTitleType.TextNormal1())
PkTitle("内文2加粗", PkTitleType.TextBold2())
PkTitle("内文2正常", PkTitleType.TextNormal2())
}
3.3. NavBar导航栏
3.3.1. 介绍
PkNavBar 是一个自定义的 Compose 顶部导航栏组件,适用于需要实现自定义标题栏、返回按钮、右侧操作按钮等功能的场景。
支持沉浸式状态栏背景设置、返回事件处理、右侧图标点击事件处理、标题样式自定义等功能。
3.3.2. 参数
| 参数名 | 参数类型 | 是否必填 | 说明 |
|---|---|---|---|
title | String | 是 | 导航栏标题文本 |
backgroundColor | Color | 否 | 背景颜色,默认 #FFFFFEFA |
horizontalContentPadding | Dp | 否 | 水平内边距,默认 BasicSpace.space_18 |
verticalContentPadding | Dp | 否 | 垂直内边距,默认 BasicSpace.space_10 |
backResource | @DrawableRes Int | 否 | 返回按钮图标资源 ID,默认 R.drawable.compose_icon_retrun |
backResourceSize | Dp | 否 | 返回图标尺寸,默认 BasicSize.size_24 |
showBack | Boolean | 否 | 是否显示返回按钮,默认 true |
onBackClick | (() -> Unit)? | 否 | 返回按钮点击事件,默认 null(默认行为为关闭 Activity) |
titleFontSize | TextUnit | 否 | 标题文字大小,默认 BasicFont.font_18 |
titleColor | Color | 否 | 标题文字颜色,默认 #1F401B |
isImmersive | Boolean | 否 | 是否沉浸式状态栏(设置状态栏颜色),默认 true |
darkIcons | Boolean | 否 | 状态栏图标是否为深色,默认 true |
rightResource | @DrawableRes Int? | 否 | 右侧图标资源 ID,可为空表示不显示 |
onRightClick | (() -> Unit)? | 否 | 右侧图标点击事件,为空则不响应点击 |
3.3.3. 示例代码
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
PkNavBar("默认NavBar导航栏")
PkNavBar("我是长文本的NavBar导航栏,超长的,但是不显示右边按钮")
PkNavBar(
"我是长文本的NavBar导航栏,超长的,显示右边按钮",
rightResource = R.drawable.ic_menu
)
PkNavBar("自定义返回事件", onBackClick = {
Toast.makeText(context,"自定义返回事件",Toast.LENGTH_LONG).show()
})
}
3.4. 单元格组件
3.4.1. 介绍
PkCell 是一个通用的列表项/单元格组件,基于 Jetpack Compose 实现。核心功能如下:
- 左右布局结构:左侧固定显示文本标题,右侧支持灵活组合文本、图标和交互动画或完全自定义内容(图标、开关、文本等)
- 标题样式继承自
PkTitle组件,支持预定义的标题类型(PkTitleType) - 内置点击动画:支持右侧图标的旋转动画(如展开/收起场景)
- 自动处理文本溢出(默认截断为省略号)
- 适用于设置项、菜单项、信息展示等需要左右结构的场景
3.4.2. 参数说明——右侧支持灵活组合文本、图标和交互动画
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| text | String | 是 | 无 | 左侧主标题文本内容 |
| type | PkTitleType | 否 | PkTitleType.BigTitle1() | 标题样式类型(字体大小、字重),参考 PkTitleType文档 |
| modifier | Modifier | 否 | Modifier | 整体容器修饰符(如边距、背景等) |
| color | Color | 否 | Color(0xFF333333) | 左侧标题文本颜色 |
| fontStyle | FontStyle? | 否 | null | 字体风格(如斜体 FontStyle.Italic) |
| textAlign | TextAlign? | 否 | null | 文本对齐方式(默认跟随系统) |
| overflow | TextOverflow | 否 | TextOverflow.Ellipsis | 文本溢出处理方式 |
| maxLines | Int | 否 | 1 | 文本最大显示行数 |
| style | TextStyle | 否 | LocalTextStyle.current | 自定义文本样式(覆盖 type属性) |
| rightText | String | 否 | "" | 右侧辅助文本内容(空字符串时不显示) |
| rightTextColor | Color | 否 | Color(0xFF666666) | 右侧辅助文本颜色 |
| rightTextSize | TextUnit | 否 | 12.sp | 右侧辅助文本字体大小 |
| rightIcon | @DrawableRes Int? | 否 | R.drawable.ic_right_arrow | 右侧图标资源 ID(设为 null时不显示图标) |
| rightIconSize | Dp | 否 | 12.dp | 右侧图标尺寸 |
| isRightIconRotated | Boolean | 否 | false | 是否启用图标旋转动画(用于展开/收起状态指示) |
| rightClick | (() -> Unit)? | 否 | null | 点击右侧区域回调(触发动画和自定义逻辑) |
Column(
Modifier
.background(Color.White)
.fillMaxSize()
) {
PkCell(
"常用功能",
PkTitleType.BigTitle3(),
rightText = "展开",
modifier = Modifier.padding(horizontal = 18.dp),
color = Color(0xFF14401B)
)
}
3.4.3. 参数说明——自定义右边内容
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
text | String | 是 | 无 | 左侧显示的文本内容 |
type | PkTitleType | 否 | PkTitleType.BigTitle1() | 标题样式类型(字体大小、字重等),参考 PkTitleType文档 |
modifier | Modifier | 否 | Modifier | 布局修饰符(如尺寸、边距等),作用于整个单元格容器 |
color | Color | 否 | Color(0xFF333333) | 文本颜色 |
fontStyle | FontStyle? | 否 | null | 字体风格(如斜体 FontStyle.Italic) |
textAlign | TextAlign? | 否 | null | 文本对齐方式(如 TextAlign.End右对齐),默认跟随系统 |
overflow | TextOverflow | 否 | TextOverflow.Ellipsis | 文本溢出处理方式(默认显示省略号) |
maxLines | Int | 否 | 1 | 文本最大显示行数 |
style | TextStyle | 否 | LocalTextStyle.current | 自定义文本样式(可覆盖 type中的部分属性) |
rightContent | @Composable RowScope.() -> Unit | 是 | 无 | 右侧自定义内容(可放置图标、开关等组件),通过 RowScope支持灵活布局 |
// 基础用法(右侧带箭头图标)
PkCell(
text = "个人资料",
type = PkTitleType.TitleBold1(),
modifier = Modifier.padding(16.dp),
rightContent = {
Icon(
imageVector = Icons.Default.ArrowForward,
contentDescription = "进入",
tint = Color.Gray
)
}
)
// 复杂右侧内容(文字 + 开关)
PkCell(
text = "夜间模式",
color = Color.Black,
rightContent = {
Text("已开启", color = Color.Gray)
Spacer(Modifier.width(8.dp))
Switch(
checked = isDarkMode,
onCheckedChange = { /* 状态更新逻辑 */ }
)
}
)
3.5. 按钮组件
3.5.1. 介绍
PkButton 是一个基于 Jetpack Compose 的标准化按钮组件,封装了 Material Design 的 Button 并扩展了预设样式。核心功能如下:
- 统一设计规范:预定义按钮形状、颜色、内边距等样式,保证应用内按钮一致性
- 灵活扩展:支持覆盖默认样式(如颜色、阴影、边框)
- 交互状态集成:自动处理点击、禁用、按压等状态的视觉效果
- 内容自定义:支持嵌入任意组合的文本、图标或其他组件
3.5.2. 参数
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
onClick | () -> Unit | 是 | 无 | 按钮点击事件回调 |
modifier | Modifier | 否 | Modifier | 布局修饰符(如尺寸、边距、背景等) |
enabled | Boolean | 否 | true | 是否启用按钮(禁用时自动降低透明度并禁用点击事件) |
interactionSource | MutableInteractionSource | 否 | remember { MutableInteractionSource() } | 用于自定义按钮交互状态(如按压、悬停效果) |
elevation | ButtonElevation? | 否 | ButtonDefaults.elevation() | 按钮阴影效果(设为 null可移除阴影) |
shape | Shape | 否 | PkTheme.shapes.small | 按钮形状(默认使用主题的小圆角,如 RoundedCornerShape(4.dp)) |
border | BorderStroke? | 否 | null | 按钮边框(如 BorderStroke(1.dp, Color.Gray) ) |
colors | ButtonColors | 否 | PkButtonDefault.buttonColors() | 按钮颜色配置(含默认、禁用、按压等状态颜色) |
contentPadding | PaddingValues | 否 | PkButtonDefault.ContentPadding | 内容内边距(默认 PaddingValues(horizontal=16.dp, vertical=8.dp) ) |
content | @Composable RowScope.() -> Unit | 是 | 无 | 按钮内容(支持 RowScope布局,如文本+图标组合) |
3.5.3. 示例
Row(horizontalArrangement = Arrangement.spacedBy(10.dp), modifier = Modifier.padding(top=20.dp, start = 20.dp)) {
PkButton(
onClick = {
}, elevation = null,
colors = PkButtonDefault.transparentColor(),
shape = PkTheme.shapes.medium,
border = BorderStroke(0.5.dp, Color(0xFFD4D4D5))
) {
Text(
"继续挑战", fontWeight = FontWeight.W500,
fontSize = BasicFont.font_12
)
}
PkButton(
onClick = {
},
elevation = null,
colors = PkButtonDefault.buttonColors(),
shape = PkTheme.shapes.medium,
) {
Text(
"领取任务", fontWeight = FontWeight.W500,
fontSize = BasicFont.font_12
)
}
}
3.6. 图片组件
3.6.1. 介绍
PkImageView 是一个基于 Jetpack Compose 的定制化图片展示组件,对原生 Image 组件进行了封装,提供更简洁的默认配置和常用功能扩展。核心特性包括:
- 预设常用参数:默认居中裁剪、支持透明度调整
- 颜色滤镜:一键添加统一色调(
tintColor) - 可访问性简化:默认隐藏内容描述(需根据场景手动添加)
- 无缝兼容:保留原生
Image的所有能力,支持深度定制
3.6.2. 参数说明
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
painter | Painter | 是 | 无 | 图片资源(支持 painterResource、rememberAsyncImagePainter等) |
modifier | Modifier | 否 | Modifier | 布局修饰符(尺寸、边距、背景等) |
alignment | Alignment | 否 | Alignment.Center | 图片在容器内的对齐方式 |
contentScale | ContentScale | 否 | ContentScale.Crop | 图片缩放模式(如填充 FillBounds、适应 Fit等) |
alpha | Float | 否 | DefaultAlpha(1.0F) | 透明度(范围 0.0f完全透明 - 1.0f不透明) |
tintColor | Color? | 否 | null | 颜色滤镜(如 Color.Blue将图片染成蓝色),null表示不应用滤镜 |
3.6.3. 示例
@Composable
fun ImagePage() {
val imageUrl="https://coil-kt.github.io/coil/images/coil_logo_black.svg"
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
PkNavBar("图片组件")
Column {
PkTitle("加载本地图片", type = PkTitleType.BigTitle3())
PkImageView(painter = painterResource(R.drawable.portrair), modifier = Modifier.size(80.dp))
}
Column {
PkTitle("加载网络图片", type = PkTitleType.BigTitle3())
PkImageView(painter =ImagePainterUtils.getPainter(imageUrl), modifier = Modifier.size(80.dp))
}
Column {
PkTitle("加载网络图片,并修改颜色为红色", type = PkTitleType.BigTitle3())
PkImageView(painter = ImagePainterUtils.getPainter(imageUrl), tintColor = Color.Red,modifier = Modifier.size(80.dp))
}
}
}
4. 展示组件
4.1. 网格布局
4.1.1. 介绍
P kGridLayout 是一个基于 Jetpack Compose 实现的网格布局组件,支持动态生成多行多列的布局结构。核心功能包括:
- 自定义列数与列间距:灵活控制每行列数和列间空白
- 自适应填充:自动计算行数,不足一行的位置用空白占位
- 分割线支持:可显示水平分割线,支持自定义分割线样式
- 高性能渲染:适用于中小规模数据集(非惰性加载,适合固定或少量数据场景)
4.1.2. 参数
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
columns | Int(取值范围 ≥1) | 是 | 无 | 每行显示的列数 |
data | MutableList<E> | 是 | 无 | 数据源列表,泛型 E表示数据项类型 |
isShowHorizontalDivider | Boolean | 否 | false | 是否显示水平分割线(仅在行之间显示) |
divider | @Composable (() -> Unit)? | 否 | null | 自定义分割线组件,若未提供且 isShowHorizontalDivider=true,则使用默认 Divider |
| columnSpacing | Dp | 否 | 12.dp | 列之间的水平间距 |
content | @Composable (Int, E) -> Unit | 是 | 无 | 定义每个网格项的内容,参数为数据项索引和对应的数据项 E |
4.1.3. 示例代码
@Composable
fun GridPage() {
val dataList = mutableListOf("A", "B", "C", "D", "E", "F", "G")
Column(modifier = Modifier.padding(horizontal = 15.dp)) {
PkNavBar("网格布局")
// 基础用法(2列,带列间距和默认分割线)
PkGridLayout(
columns = 2,
data = dataList,
isShowHorizontalDivider = true,
columnSpacing = 16.dp,
divider = {
PkSpacer(isHorizontal = true)
}
) { index, item ->
Text(
text = "$item${index + 1}",
modifier = Modifier
.background(Color.LightGray, RoundedCornerShape(8.dp))
.padding(vertical = 8.dp)
.fillMaxWidth()
)
}
}
}
4.2. 分割线
4.2.1. PkDivider分割线
4.2.1.1. 介绍
- 支持设置水平/垂直 虚线或实线分割线
- PkDashDivider(虚线)和 PkFullDivider(实线)整合类
4.2.1.2. 导入依赖
import com.peakmain.compose.ui.divier.PkDivider
4.2.1.3. 参数
| 参数名 | 参数类型 | 说明 |
|---|---|---|
| modifier | Modifier | 用于添加额外修饰符的 Modifier。 |
| color | Color | 分隔线的颜色,默认为 0xFFF1EFE9。 |
| height | Dp | 分隔线的高度,仅在垂直分隔线生效,默认为 28.dp。 |
| thickness | Dp | 分隔线的厚度,仅在非虚线时生效,默认为 1.dp。 |
| startIndent | Dp | 分隔线的起始缩进,仅在非虚线时生效,默认为 0.dp。 |
| isHorizontal | Boolean | 是否为水平分隔线,默认为 false。 |
| isDash | Boolean | 是否绘制虚线分隔线,默认为 false。 |
| strokeWidth | Dp | 虚线的宽度,仅在绘制虚线时生效,默认为 0.5.dp。 |
| dashLength | Dp | 虚线的线段长度,仅在绘制虚线时生效,默认为 2.dp。 |
| gapLength | Dp | 虚线的间隔长度,仅在绘制虚线时生效,默认为 2.dp。 |
4.2.1.4. 示例代码
//默认垂直实线
PkDivider()
//水平实线
PkDivider(modifier = Modifier.padding(top = 10.dp), isHorizontal = true)
//垂直虚线
PkDivider(isDash=true)
//水平虚线
PkDivider(modifier = Modifier.padding(top = 10.dp), isHorizontal = true, isDash = true)
4.2.2. PkFullDivider实线分割线
4.2.2.1. 介绍
- 创建一个水平/垂直实线分隔线组件
4.2.2.2. 导入依赖
import com.peakmain.compose.ui.divier.PkFullDivider
4.2.2.3. 参数
| 参数名 | 参数类型 | 说明 |
|---|---|---|
| modifier | Modifier | 用于添加额外修饰符的 Modifier。 |
| color | Color | 分隔线的颜色,默认为 0xFFF1EFE9。 |
| height | Dp | 分隔线的高度,垂直方向生效默认为 28.dp。 |
| thickness | Dp | 分隔线的厚度,默认为 1.dp。 |
| startIndent | Dp | 分隔线的起始缩进,默认为 0.dp。 |
| isHorizontal | Boolean | 水平分割线 (true)/ 垂直分割线 (false),默认是 false |
4.2.2.4. 示例代码
PkFullDivider(modifier = Modifier.padding(top = 10.dp), isHorizontal = true)
4.2.3. PkDashDivider虚线分割线
4.2.3.1. 介绍
- 创建一个水平/垂直虚线分隔线组件
4.2.3.2. 导入依赖
import com.peakmain.compose.ui.divier.PkDashDivider
4.2.3.3. 参数
| 参数名 | 参数类型 | 说明 |
|---|---|---|
| modifier | Modifier | 用于添加额外修饰符的 Modifier。 |
| color | Color | 分隔线的颜色,默认为 0xFFF1EFE9。 |
| height | Dp | 分隔线的高度,垂直方向生效,默认为 28.dp。 |
| strokeWidth | Dp | 虚线的宽度,默认为 0.5.dp。 |
| dashLength | Dp | 虚线的长度,默认为 2.dp。 |
| gapLength | Dp | 虚线之间的间隔长度,默认为 2.dp。 |
| isHorizontal | Boolean | 水平分割线 (true)/ 垂直分割线 (false),默认是 false |
4.2.3.4. 示例代码
PkDashDivider(modifier = Modifier.padding(top = 10.dp), isHorizontal = true)
4.3. 流式布局PkFlowRow
4.3.1. 介绍
PkFlowRow 是一个定制化的流式布局组件,基于 Jetpack Compose 的 FlowRow 扩展而来。核心功能如下:
- 支持子项水平排列,自动换行
- 限制最大行数(超出部分自动隐藏)
- 可自定义子项间水平/垂直间距
- 自动裁剪超出最大高度的内容(通过
clipToBounds实现) - 适用于标签组、动态分类展示等需要紧凑布局的场景
4.3.2. 参数
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| modifier | Modifier | 否 | Modifier | 布局修饰符(如尺寸、背景等),会与内部修饰符合并 |
| horizontalSpacing | Dp | 否 | 0.dp | 子项之间的水平间距 |
| verticalSpacing | Dp | 否 | 0.dp | 行之间的垂直间距 |
| maxLine | Int(取值范围 ≥1) | 否 | 2 | 最大显示行数,超出部分将被隐藏 |
| onLineCountChanged | Int | 否 | null | 行数回调 |
| content | @Composable () -> Unit | 是 | 无 | 子项内容,支持任意Composable 组件 |
4.3.3. 示例代码
@Preview
@Composable
fun PkFlowRowPreview() {
val tags = listOf("Android", "Kotlin", "Jetpack Compose", "KMP","Material Design", "UI", "Development")
PkFlowRow(
horizontalSpacing = 8.dp,
verticalSpacing = 12.dp,
maxLine = 1
) {
tags.forEach { tag ->
Text(
text = tag,
modifier = Modifier
.background(Color.LightGray, RoundedCornerShape(16.dp))
.padding(horizontal = 12.dp, vertical = 8.dp)
)
}
}
}
@Composable
fun FlowRowPage() {
val tags = listOf(
"Android",
"Kotlin",
"Jetpack Compose",
"KMP",
"Material Design",
"UI",
"Development"
)
var currentLine by remember {
mutableStateOf(0)
}
var isExpand by remember {
mutableStateOf(false)
}
Column(modifier = Modifier.fillMaxSize()) {
Column(modifier = Modifier.padding(top = 40.dp)) {
if (currentLine > 2) {
PkCell(
"超过2行显示展开/更多",
type = PkTitleType.TextBold1(),
rightText = if (!isExpand) "展开" else "收起",
rightIcon= if (isExpand) R.drawable.ic_expend_arrow_down else R.drawable.ic_expend_arrow_up,
rightClick = {
isExpand = !isExpand
}
)
}
PkFlowRow(
modifier = Modifier.padding(top = BasicSize.size_12),
horizontalSpacing = 8.dp,
verticalSpacing = 12.dp,
maxLine = if (isExpand) Int.MAX_VALUE else 2,
onLineCountChanged = {
currentLine = it
}) {
tags.forEach { tag ->
Text(
text = tag,
modifier = Modifier
.background(Color.LightGray, RoundedCornerShape(16.dp))
.padding(horizontal = 12.dp, vertical = 8.dp)
)
}
}
}
}
}
4.4. 轮播图
4.4.1. 介绍
PkBanner 是一个基于 Jetpack Compose 的横向轮播图组件,支持自动播放、手动滑动交互和点击事件。核心特性包括:
- 自适应屏幕宽度,支持居中显示轮播项
- 自动轮播功能(可配置间隔时间)
- 自定义轮播项尺寸、间距和内容
- 触摸交互时暂停自动播放(防止误操作)
- 支持单页或多页布局模式
- 支持水平/垂直轮播
4.4.2. 参数
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
lists | ArrayList<T> | 是 | 无 | 轮播数据源(若为空数组,组件不渲染) |
pagerWidth | Dp | 否 | 290.dp | 单个轮播项的宽度 |
pagerHeight | Dp | 否 | 116.dp | 轮播容器的高度 |
pageSpacing | Dp | 否 | 12.dp | 轮播项之间的水平间距 |
contentPadding | Dp | 否 | 18.dp | 首尾项两侧的边距(用于居中显示) |
duration | Long | 否 | 3000 | 自动轮播间隔时间(单位:毫秒) |
isAutoPlay | Boolean | 否 | true | 是否启用自动轮播 |
| initialPage | Int | 否 | 0 | 初始显示的页面索引(从0开始),超出范围时自动修正为有效值0 |
| onBannerClick | ((Int, T?) -> Unit)? | 否 | null | 点击轮播项的回调,参数为当前页索引 |
| isVertical | boolean | 否 | false | 垂直还是水平轮播,默认是水平 |
| horizontalAlignment | Alignment | 否 | Alignment.Start | 横向对齐方式 |
| verticalAlignment | Alignment | 否 | Alignment.CenterVertically | 内容的垂直对齐方式 |
| userScrollEnabled | Boolean | 否 | true | 是否允许用户手动滑动 |
| forceContentPaddingZero | Boolean | 否 | false | 是否强制内容边距为 0 只对水平轮播有作用 |
| content | @Composable (Int, T?) -> Unit | 是 | 无 | 定义轮播项内容,参数为当前页索引 |
4.4.3. 示例代码
@Composable
fun BannerPage() {
val lists = ArrayList<String>().apply {
add("https://img2.baidu.com/it/u=292395973,2170347184&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800")
add("https://img0.baidu.com/it/u=3492687357,1203050466&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500")
add("https://img2.baidu.com/it/u=2843793126,682473204&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800")
add("https://img1.baidu.com/it/u=3907217777,761642486&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800")
add("https://img1.baidu.com/it/u=1082651511,4058105193&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800")
}
Column(
modifier = Modifier
.background(Color.White)
.fillMaxSize()
) {
PkBanner(
lists,
isAutoPlay = true,
initialPage = 3,
onBannerClick = {index,item->
Log.e("TAG", "获取到点击后的数据:${item}")
}) {index,item->
Image(
painter = ImagePainterUtils.getPainter(item),
contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(8.dp))
.fillMaxSize(),
contentScale = ContentScale.Crop,
alignment = Alignment.TopCenter
)
}
}
}
垂直轮播
@Composable
fun BannerPage() {
val vLists = arrayListOf("广告", "我是垂直轮播", "生活好滋味,就要上四休三")
val itemWidth = (LocalConfiguration.current.screenWidthDp.dp)
PkBanner(
vLists,
isAutoPlay = true,
isVertical = true,
pagerHeight = 88.dp,
pagerWidth = itemWidth
) { index, item ->
Box() {
Column(
modifier = Modifier
.clip(RoundedCornerShape(BasicRadius.radius_8))
.background(PkColor.color_fill2)
.padding(bottom = BasicSpace.space_16)
.fillMaxSize(),
) {
Box() {
Column {
Row(
modifier = Modifier
.padding(
top = BasicSpace.space_16,
start = BasicSpace.space_12,
end = BasicSpace.space_12
),
) {
// 左侧 圆形背景 + 图标
Box(
modifier = Modifier
.size(BasicSize.size_40)
.clip(CircleShape)
.background(PkColor.color_fill1),
contentAlignment = Alignment.Center
) {
PkImageView(
painter = painterResource(
id = R.drawable.ic_online_check_out_disable
),
modifier = Modifier.size(BasicSize.size_24),
)
}
Spacer(modifier = Modifier.width(BasicSpace.space_8))
// 中间 内容
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "已入住",
color = PkColor.color_text1,
fontSize = BasicFont.font_14,
)
Spacer(modifier = Modifier.height(BasicSize.size_2))
Text(
text = "2025年06月27日" + " | " + "金会员",
color = PkColor.color_text2,
fontSize = BasicFont.font_11,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
// 底部进度条
RoundedLinearProgressIndicator(
progress = 0.5f,
modifier = Modifier
.padding(top = BasicSize.size_12)
.fillMaxWidth()
.height(BasicSize.size_4)
.padding(horizontal = BasicSpace.space_16),
color = PkColor.color_brand1,
cornerRadius = BasicRadius.radius_2
)
PkSpacer(height = BasicSize.size_16)
}
//洗衣取送
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(end = BasicSpace.space_8)
.align(Alignment.TopEnd)
) {
Image(
painter = painterResource(id = R.drawable.background_laundry_delivery),
contentDescription = null,
contentScale = ContentScale.FillBounds,
modifier = Modifier
.wrapContentWidth()
.wrapContentHeight()
)
androidx.compose.material3.Text(
text = "垂直轮播",
color = PkColor.color_text5,
fontSize = BasicFont.font_11,
modifier = Modifier
.padding(
horizontal = BasicSpace.space_7,
vertical = BasicSpace.space_4
)
)
}
}
}
}
}
}
4.5. 高亮文本
4.5.1. 介绍
PkHighlightText 是一个基于 Jetpack Compose 的文本高亮组件,支持在长文本中多关键字高亮显示,特性如下:
- 智能匹配:支持不区分大小写、自动合并重叠高亮区间
- 安全转义:自动处理正则表达式特殊字符(如
$,*,+等) - 灵活样式:可自定义高亮颜色,继承外部文本样式(字体大小、字重等)
- 鲁棒性:空关键字/非法正则表达式自动降级为普通文本
- 重叠区间:自动合并(如
0..5和3..8→0..8)
4.5.2. 参数说明
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
text | String | 是 | 无 | 需要处理的原始文本 |
keywords | List<String> | 是 | 无 | 高亮关键字列表(空列表时不进行高亮) |
highlightColor | Color | 否 | Color.Red | 高亮文本颜色 |
style | TextStyle | 否 | LocalTextStyle.current | 基础文本样式(如字体大小、字重),高亮部分继承此样式并叠加颜色 |
4.5.3. 示例
// 示例1:基本用法(多个关键字)
PkHighlightText(
text = "Jetpack Compose 是 Android 的现代 UI 工具包",
keywords = listOf("compose", "android"),
highlightColor = Color.Blue,
style = MaterialTheme.typography.body1
)
// 示例2:含特殊字符的关键字
PkHighlightText(
text = "价格:$199 (限时优惠)",
keywords = listOf("$199", "(限时优惠)"),
highlightColor = Color(0xFF4CAF50)
)
// 示例3:无关键字/空列表
PkHighlightText(
text = "Hello World",
keywords = emptyList() // 显示普通文本
)
4.6. 瀑布流
4.6.1. 介绍
PkStaggeredVerticalGrid 是一个基于 Jetpack Compose 的瀑布流布局组件,专为呈现高度不规则的网格内容设计(如图片墙、卡片集合)。通过智能分配元素到最短列,实现自然错落的视觉效果,同时保证高效的空间利用率。
4.6.2. 参数
| 参数名 | 参数类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| columns | Int | 是 | 无 | 网格列数(必须 ≥1) |
| modifier | Modifier | 否 | Modifier | 容器修饰符(背景、尺寸、滚动等) |
| contentPadding | PaddingValues | 否 | 0.dp | 内容区域的内边距(支持独立设置各方向) |
| verticalItemSpacing | Dp | 否 | 8.dp | 垂直方向(行间)间距 |
| horizontalItemSpacing | Dp | 否 | 8.dp | 水平方向(列间)间距 |
| content | @Composable () -> Unit | 是 | 无 | 网格项内容(任意 Composable 组件) |
4.6.3. 示例
@Composable
fun StaggeredVerticalGridPage() {
// 生成示例数据(包含随机高度)
val items = List(15) { index ->
StaggeredItem(
id = index, height = (20 + Random.nextInt(50)).dp, // 随机高度 (120-270dp)
title = "Item ${index + 1}"
)
}
Column {
PkStaggeredVerticalGrid(
columns = 2,
contentPadding = PaddingValues(16.dp),
verticalItemSpacing = 4.dp,
horizontalItemSpacing = 16.dp, // 水平间距
modifier = Modifier.wrapContentHeight()
) {
items.forEach { item ->
Box(
modifier = Modifier
.fillMaxWidth()
.background(
Color(
red = Random.nextInt(256),
green = Random.nextInt(256),
blue = Random.nextInt(256),
alpha = 255
)
),
) {
Box(
modifier = Modifier
.fillMaxSize(), contentAlignment = Alignment.Center
) {
Text(
text = item.title,
color = Color.White,
modifier = Modifier.padding(8.dp)
)
}
}
}
}
}
}
5. 工具类
5.1. ImagePainterUtils工具类
5.1.1. 介绍
- 根据图片 URL 获取 AsyncImagePainter 对象
5.1.2. 导入依赖
import com.peakmain.compose.utils.ImagePainterUtils
5.1.3. 参数
| 参数名 | 参数类型 | 说明 |
|---|---|---|
| imageUrl | String | 图片的 URL,如果为空则显示占位图。 |
| errorDrawableResId | Int | 图片加载失败时显示的 Drawable 资源 ID,默认为 R.drawable.icon_loading。 |
| placeDrawableResId | Int | 图片加载过程中显示的占位图 Drawable 资源 ID,默认为 R.drawable.icon_loading。 |
5.1.4. 示例代码
Image(
painter = ImagePainterUtils.getPainter(it.imageUrl),
contentDescription = null,
modifier = Modifier
.clip(RoundedCornerShape(8.dp))
.weight(1f)
.height(75.dp),
contentScale = ContentScale.Crop
)
6. 扩展类
6.1. List扩展类
6.1.1. 介绍
可空List的扩展类,作用如下
- 可空List的大小
- 可空List的大小是否大于0
- 可空List大小是否为0
- 截取 List 的子区间
[fromIndex, toIndex),返回子列表
6.1.2. 导入依赖
import com.peakmain.compose.ext.orSize
6.1.3. 方法
| 方法名 | 返回值 | 参数 | 说明 |
|---|---|---|---|
| orSize | Int | 无 | 获取 List 的大小。若 List 为 null,则返回 0;若 List 不为 null,则返回其 size。 |
| sizeBigZero | Boolean | 无 | 判断 List 大小是否大于 0。若 List 为 null,则返回 false;若 List 不为 null,则判断其大小是否大于 0。 |
| sizeEqualZero | Boolean | 无 | 判断 List 的大小是否为 0。若 List 为 null,则返回 true;若 List 不为 null,则判断其大小是否等于 0。 |
| slice | List | ①、fromIndex:起始索引(包含),需满足 fromIndex >= 0②、toIndex结束索引(不包含),需满足 toIndex <= size 且 toIndex >= fromIndex | 此函数用于获取当前列表(可能为 null)在指定索引范围 [fromIndex, toIndex) 内的子列表视图。若原列表为 null、范围无效或超出实际大小,则直接返回原列表 |
6.1.4. 示例代码
@Composable
fun ListExtPage() {
val list1: List<String>? = null
val list2 = arrayListOf("list1", "list2", "list3", "list4")
CpColumn("List扩展类") {
CpTitle("空数组list1的大小:${list1.orSize()}")
CpTitle("空数组list1的大小是否等于0:${list1.sizeBigZero()}")
CpTitle("空数组list1的大小是否大于0:${list1.sizeBigZero()}")
CpTitle("定索引范围 [fromIndex, toIndex) 内的子列表视图")
var result: String = "结果是:"
list2.slice(1, 3)?.forEach {
result +="$it,"
}
Text(result, fontSize = BasicFont.font_10, color = PkColor.color_text1, modifier = Modifier.padding(horizontal = 18.dp))
}
}
6.2. String扩展类
6.2.1. 介绍
这组扩展函数为 String? 类型提供了增强的空安全操作,支持链式调用与条件执行逻辑
6.2.2. 导入依赖
import com.peakmain.compose.ext.*
6.2.3. 方法
| 函数签名 | 功能描述 | 返回值规则 |
|---|---|---|
fun String?.isEmpty(): Boolean | 检查字符串是否为 null或空字符串("") | true表示空或 null |
fun String?.isEmpty(block: () -> Unit): String? | 若字符串为空或 null,执行 block逻辑,保持链式调用 | 返回原字符串(this) |
fun String?.isNotEmpty(): Boolean | 检查字符串非空且非 null | true表示有内容 |
fun String?.isNotEmpty(block: (String) -> Unit): String? | 若字符串非空且非 null,执行 block并将非空字符串传入,保持链式调用 |
6.2.4. 与 Kotlin 标准库对比
| 场景 | 本扩展函数 | Kotlin 标准库 |
|---|---|---|
| 空检查 | text.isEmpty() | text.isNullOrEmpty() |
| 非空检查 | text.isNotEmpty() | text.isNullOrEmpty().not() |
| 带逻辑的空检查 | text.isEmpty { ... } | text?.takeIf { it.isEmpty() }?.also { ... } |
| 带逻辑的非空检查 | text.isNotEmpty { ... } | text?.let { ... } |
6.2.5. 示例代码
6.2.5.1. 优化前后场景
- 以前代码逻辑
if (userInfo != null && !TextUtils.isEmpty(userInfo.nickName))
userInfo.nickName
else
"登录/注册",
- 优化后代码
if (userInfo?.nickName.isNotEmpty())
userInfo!!.nickName
else
"登录/注册",
或者
text= userInfo?.nickName.isNotEmpty {it}?: "登录/注册",
6.2.5.2. 其他场景示例:
// 场景:仅在非空时打印内容并转为大写
val result = nullableString
.isNotEmpty {
println("Processing: $it")
it.uppercase()
}.isEmpty{
}
// 场景:空值时显示默认文本
nullableString
.isEmpty { showError("内容不能为空!") }
?.let { updateUI(it) }