CmComposeUI —— 基于 Kotlin Multiplatform Compose 的 UI 组件库

0 阅读18分钟

版本号

CmComposeUI 是一个基于 Kotlin Multiplatform Compose 的 UI 组件库,提供丰富的通用组件,支持 Android 和 iOS 双平台。

引入使用

在项目根目录 settings.gradle.kts 添加 JitPack 仓库:

dependencyResolutionManagement {
    repositories {
        maven { url = uri("https://jitpack.io") }
    }
}

在共享代码模块 composeApp/src/commonMain/kotlinbuild.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 内容,默认居中显示)
modifierModifierModifier布局修饰符,会与组件内部修饰符合并
navigationIcon@Composable (() -> Unit)?null左侧导航图标(如返回按钮),若为 null则不显示
backgroundColorColorMaterialTheme.colors.primarySurface应用栏背景颜色
actions@Composable RowScope.() -> Unit{}右侧操作图标组(可包含多个图标按钮)
isImmersiveBooleanfalse是否启用沉浸式状态栏(透明状态栏,内容向上延伸)
darkIconsBooleanfalse状态栏图标颜色是否为深色(true为黑色,false为白色),仅在 isImmersive=true时生效
content@Composable (PaddingValues) -> Unit页面主体内容(通过 Scaffold插入到应用栏下方)

3.1.3. 示例代码

image.png

@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. 参数说明

参数名参数类型是否必填说明
textString需要显示的文本内容
typePkTitleType标题类型(默认为 BigTitle1),支持选择预定义的标题样式(如大标题、小标题、内文等)
modifierModifier布局修饰符(默认 Modifier),用于调整文本的布局、尺寸、间距等
colorColor文本颜色(默认 0xFF333333
fontStyleFontStyle?字体风格(如斜体 FontStyle.Italic),默认 null表示不设置
textAlignTextAlign?文本对齐方式(如居中 TextAlign.Center),默认 null表示继承父布局对齐
overflowTextOverflow文本溢出处理方式(默认 TextOverflow.Clip),支持 Ellipsis等效果
maxLinesInt文本最大行数(默认无限制 Int.MAX_VALUE
styleTextStyle自定义文本样式(默认 LocalTextStyle.current),可覆盖 type中的部分属性

3.2.3. PkTitleType 类型说明

PkTitleType 是一个密封类,定义了以下预置样式:

类型名称字体大小字重说明
BigTitle124.spW500大标题1(默认类型)
BigTitle222.spW500大标题2
BigTitle318.spW500大标题3
TitleBold116.spW500标题1(加粗)
TitleNormal116.spW400标题1(常规)
TitleBold215.spW500标题2(加粗)
TitleNormal215.spW400标题2(常规)
SmallTitleBold14.spW500小标题(加粗)
SmallTitleNormal14.spW400小标题(常规)
TextBold112.spW500内文1(加粗)
TextNormal112.spW400内文1(常规)
TextBold211.spW500内文2(加粗)
TextNormal211.spW400内文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. 参数

参数名参数类型是否必填说明
titleString导航栏标题文本
backgroundColorColor背景颜色,默认 #FFFFFEFA
horizontalContentPaddingDp水平内边距,默认 BasicSpace.space_18
verticalContentPaddingDp垂直内边距,默认 BasicSpace.space_10
backResource@DrawableRes Int返回按钮图标资源 ID,默认 R.drawable.compose_icon_retrun
backResourceSizeDp返回图标尺寸,默认 BasicSize.size_24
showBackBoolean是否显示返回按钮,默认 true
onBackClick(() -> Unit)?返回按钮点击事件,默认 null(默认行为为关闭 Activity)
titleFontSizeTextUnit标题文字大小,默认 BasicFont.font_18
titleColorColor标题文字颜色,默认 #1F401B
isImmersiveBoolean是否沉浸式状态栏(设置状态栏颜色),默认 true
darkIconsBoolean状态栏图标是否为深色,默认 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. 参数说明——右侧支持灵活组合文本、图标和交互动画

参数名参数类型是否必填默认值说明
textString左侧主标题文本内容
typePkTitleTypePkTitleType.BigTitle1()标题样式类型(字体大小、字重),参考 PkTitleType文档
modifierModifierModifier整体容器修饰符(如边距、背景等)
colorColorColor(0xFF333333)左侧标题文本颜色
fontStyleFontStyle?null字体风格(如斜体 FontStyle.Italic
textAlignTextAlign?null文本对齐方式(默认跟随系统)
overflowTextOverflowTextOverflow.Ellipsis文本溢出处理方式
maxLinesInt1文本最大显示行数
styleTextStyleLocalTextStyle.current自定义文本样式(覆盖 type属性)
rightTextString""右侧辅助文本内容(空字符串时不显示)
rightTextColorColorColor(0xFF666666)右侧辅助文本颜色
rightTextSizeTextUnit12.sp右侧辅助文本字体大小
rightIcon@DrawableRes Int?R.drawable.ic_right_arrow右侧图标资源 ID(设为 null时不显示图标)
rightIconSizeDp12.dp右侧图标尺寸
isRightIconRotatedBooleanfalse是否启用图标旋转动画(用于展开/收起状态指示)
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. 参数说明——自定义右边内容

参数名参数类型是否必填默认值说明
textString左侧显示的文本内容
typePkTitleTypePkTitleType.BigTitle1()标题样式类型(字体大小、字重等),参考 PkTitleType文档
modifierModifierModifier布局修饰符(如尺寸、边距等),作用于整个单元格容器
colorColorColor(0xFF333333)文本颜色
fontStyleFontStyle?null字体风格(如斜体 FontStyle.Italic
textAlignTextAlign?null文本对齐方式(如 TextAlign.End右对齐),默认跟随系统
overflowTextOverflowTextOverflow.Ellipsis文本溢出处理方式(默认显示省略号)
maxLinesInt1文本最大显示行数
styleTextStyleLocalTextStyle.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按钮点击事件回调
modifierModifierModifier布局修饰符(如尺寸、边距、背景等)
enabledBooleantrue是否启用按钮(禁用时自动降低透明度并禁用点击事件)
interactionSourceMutableInteractionSourceremember { MutableInteractionSource() }用于自定义按钮交互状态(如按压、悬停效果)
elevationButtonElevation?ButtonDefaults.elevation()按钮阴影效果(设为 null可移除阴影)
shapeShapePkTheme.shapes.small按钮形状(默认使用主题的小圆角,如 RoundedCornerShape(4.dp)
borderBorderStroke?null按钮边框(如 BorderStroke(1.dp, Color.Gray)
colorsButtonColorsPkButtonDefault.buttonColors()按钮颜色配置(含默认、禁用、按压等状态颜色)
contentPaddingPaddingValuesPkButtonDefault.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. 参数说明

参数名参数类型是否必填默认值说明
painterPainter图片资源(支持 painterResourcerememberAsyncImagePainter等)
modifierModifierModifier布局修饰符(尺寸、边距、背景等)
alignmentAlignmentAlignment.Center图片在容器内的对齐方式
contentScaleContentScaleContentScale.Crop图片缩放模式(如填充 FillBounds、适应 Fit等)
alphaFloatDefaultAlpha(1.0F)透明度(范围 0.0f完全透明 - 1.0f不透明)
tintColorColor?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. 参数

参数名参数类型是否必填默认值说明
columnsInt(取值范围 ≥1)每行显示的列数
dataMutableList<E>数据源列表,泛型 E表示数据项类型
isShowHorizontalDividerBooleanfalse是否显示水平分割线(仅在行之间显示)
divider@Composable (() -> Unit)?null自定义分割线组件,若未提供且 isShowHorizontalDivider=true,则使用默认 Divider
columnSpacingDp12.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. 参数
参数名参数类型说明
modifierModifier用于添加额外修饰符的 Modifier。
colorColor分隔线的颜色,默认为 0xFFF1EFE9。
heightDp分隔线的高度,仅在垂直分隔线生效,默认为 28.dp。
thicknessDp分隔线的厚度,仅在非虚线时生效,默认为 1.dp。
startIndentDp分隔线的起始缩进,仅在非虚线时生效,默认为 0.dp。
isHorizontalBoolean是否为水平分隔线,默认为 false。
isDashBoolean是否绘制虚线分隔线,默认为 false。
strokeWidthDp虚线的宽度,仅在绘制虚线时生效,默认为 0.5.dp。
dashLengthDp虚线的线段长度,仅在绘制虚线时生效,默认为 2.dp。
gapLengthDp虚线的间隔长度,仅在绘制虚线时生效,默认为 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. 参数
参数名参数类型说明
modifierModifier用于添加额外修饰符的 Modifier。
colorColor分隔线的颜色,默认为 0xFFF1EFE9。
heightDp分隔线的高度,垂直方向生效默认为 28.dp。
thicknessDp分隔线的厚度,默认为 1.dp。
startIndentDp分隔线的起始缩进,默认为 0.dp。
isHorizontalBoolean水平分割线 (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. 参数
参数名参数类型说明
modifierModifier用于添加额外修饰符的 Modifier。
colorColor分隔线的颜色,默认为 0xFFF1EFE9。
heightDp分隔线的高度,垂直方向生效,默认为 28.dp。
strokeWidthDp虚线的宽度,默认为 0.5.dp。
dashLengthDp虚线的长度,默认为 2.dp。
gapLengthDp虚线之间的间隔长度,默认为 2.dp。
isHorizontalBoolean水平分割线 (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. 参数

参数名参数类型是否必填默认值说明
modifierModifierModifier布局修饰符(如尺寸、背景等),会与内部修饰符合并
horizontalSpacingDp0.dp子项之间的水平间距
verticalSpacingDp0.dp行之间的垂直间距
maxLineInt(取值范围 ≥1)2最大显示行数,超出部分将被隐藏
onLineCountChangedIntnull行数回调
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. 参数

参数名参数类型是否必填默认值说明
listsArrayList<T>轮播数据源(若为空数组,组件不渲染)
pagerWidthDp290.dp单个轮播项的宽度
pagerHeightDp116.dp轮播容器的高度
pageSpacingDp12.dp轮播项之间的水平间距
contentPaddingDp18.dp首尾项两侧的边距(用于居中显示)
durationLong3000自动轮播间隔时间(单位:毫秒)
isAutoPlayBooleantrue是否启用自动轮播
initialPageInt0初始显示的页面索引(从0开始),超出范围时自动修正为有效值0
onBannerClick((Int, T?) -> Unit)?null点击轮播项的回调,参数为当前页索引
isVerticalbooleanfalse垂直还是水平轮播,默认是水平
horizontalAlignmentAlignmentAlignment.Start横向对齐方式
verticalAlignmentAlignmentAlignment.CenterVertically内容的垂直对齐方式
userScrollEnabledBooleantrue是否允许用户手动滑动
forceContentPaddingZeroBooleanfalse是否强制内容边距为 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..53..80..8

4.5.2. 参数说明

参数名参数类型是否必填默认值说明
textString需要处理的原始文本
keywordsList<String>高亮关键字列表(空列表时不进行高亮)
highlightColorColorColor.Red高亮文本颜色
styleTextStyleLocalTextStyle.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. 参数

参数名参数类型是否必填默认值说明
columnsInt网格列数(必须 ≥1)
modifierModifierModifier容器修饰符(背景、尺寸、滚动等)
contentPaddingPaddingValues0.dp内容区域的内边距(支持独立设置各方向)
verticalItemSpacingDp8.dp垂直方向(行间)间距
horizontalItemSpacingDp8.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 对象

1.gif

5.1.2. 导入依赖

import com.peakmain.compose.utils.ImagePainterUtils

5.1.3. 参数

参数名参数类型说明
imageUrlString图片的 URL,如果为空则显示占位图。
errorDrawableResIdInt图片加载失败时显示的 Drawable 资源 ID,默认为 R.drawable.icon_loading。
placeDrawableResIdInt图片加载过程中显示的占位图 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. 方法

方法名返回值参数说明
orSizeInt获取 List 的大小。若 List 为 null,则返回 0;若 List 不为 null,则返回其 size。
sizeBigZeroBoolean判断 List 大小是否大于 0。若 List 为 null,则返回 false;若 List 不为 null,则判断其大小是否大于 0。
sizeEqualZeroBoolean判断 List 的大小是否为 0。若 List 为 null,则返回 true;若 List 不为 null,则判断其大小是否等于 0。
sliceList①、fromIndex:起始索引(包含),需满足 fromIndex >= 0②、toIndex结束索引(不包含),需满足 toIndex <= sizetoIndex >= 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检查字符串非空且非 nulltrue表示有内容
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) }