Compose 自定义组件:封装一个通用标题栏

在 Android 开发中,标题栏(TopBar)可以说是几乎每个页面都会用到的基础组件。尽管 Material Design3 官方提供了 TopAppBar,但往往难以满足国内复杂的 UI 视觉规范(比如严格居中、动态的右侧操作按钮、不同的背景和字体颜色等)。

在 Jetpack Compose 这个声明式 UI 框架中,基于插槽(Slot API)和高阶函数,封装一个极具扩展性且高复用的自定义标题栏变得非常简单。

1. 需求分析:一个合格的 TopBar 需要什么?

在一个标准的 App 中,标题栏通常由三部分组成:

  • 左侧:返回按钮(有时不需要展示)。
  • 中间:页面标题文字。
  • 右侧:扩展功能区(可能是文本"提交/保存"、可能是搜索图标、也可能是分享/收藏等)。
  • 样式:灵活的背景颜色和标题颜色适配深浅色模式或主题色。

基于此,可以将自定义组件的参数设计为:

Kotlin 复制代码
@Composable
fun CommonTopBar(
    title: String,                               // 必填:标题文字
    onBackClick: (() -> Unit)? = null,           // 选填:返回点击事件,传 null 则不显示返回键
    rightContent: (@Composable () -> Unit)? = null, // 选填:右侧自定义内容(插槽)
    backgroundColor: Color = Color.White,        // 选填:背景色
    titleColor: Color = Color.Black              // 选填:文字颜色
)

2. 核心实现:声明式 UI 的魅力

看看在 Compose 中实现这样一个通用的头部组件有多简单。使用 Row 作为外层容器,并借助 Arrangement.SpaceBetween 将左中右三部分拉开。

Kotlin 复制代码
@Composable
fun CommonTopBar(...) {
    // 标题栏整体行布局
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .height(56.dp) // 标准标题栏高度
            .background(backgroundColor),
        verticalAlignment = Alignment.CenterVertically, // 垂直居中
        horizontalArrangement = Arrangement.SpaceBetween // 左右分散排列
    ) {
        // 1. 左侧:返回按钮区域
        Box(
            modifier = Modifier.padding(horizontal = 16.dp),
            contentAlignment = Alignment.Center
        ) {
            onBackClick?.let {
                Icon(
                    imageVector = Icons.Default.ArrowBack,
                    contentDescription = "返回",
                    tint = titleColor,
                    modifier = Modifier
                        .clickable { onBackClick() }
                        .padding(8.dp) // 增加点击热区
                )
            }
        }

        // 2. 中间:标题文字
        Text(
            text = title,
            fontSize = 18.sp,
            fontWeight = FontWeight.Bold,
            color = titleColor,
            maxLines = 1
        )

        // 3. 右侧:自定义扩展内容区
        Box(
            modifier = Modifier.padding(horizontal = 16.dp),
            contentAlignment = Alignment.Center
        ) {
            // 调用传入的 Composable 函数
            rightContent?.invoke()
        }
    }
}

技术亮点解析:

  1. 灵活的显隐控制 ( onBackClick?.let)
    在 Compose 中,不再需要 View.VISIBLEView.GONE。直接利用 Kotlin 的 null 安全特性,当传入的 onBackClick 函数不为空时,才渲染返回按钮。
  2. Slot API (插槽设计) ( rightContent: @Composable () -> Unit)
    这是 Compose 组件封装的灵魂!没有把右侧的内容写死成某种类型(比如写死只能传 Icon 或 String),而是接收一个 @Composable 的高阶函数。这意味着使用这个组件的人,想在右边塞什么都可以:文字、图片、甚至是进度条,极大地提升了组件的复用率。
  3. 增大点击热区 ( padding clickable的顺序)
    在 Modifier 中,修饰符的调用顺序非常重要。.clickable {}.padding(8.dp) 意味着先绑定点击事件,再内缩 8dp。这样在视觉上图标较小,但用户点击图标周围 8dp 范围内的空白处依然能触发点击,极大地改善了用户的交互体验。

3. 实战演示:一套代码,千变万化

有了这个灵活的 CommonTopBar 组件,可以轻松应对各种业务场景的页面头部:

场景 1:最简标题栏(无返回键)

适用于 App 的主页:

Kotlin 复制代码
CommonTopBar(title = "我是标题")

场景 2:普通带返回键的标题栏

只需要传入点击事件,返回按钮就会自动出现:

Kotlin 复制代码
CommonTopBar(
    title = "我是标题",
    onBackClick = { /* 执行返回逻辑 */ }
)

场景 3:右侧带文字操作按钮

适合表单填写页面:

Kotlin 复制代码
CommonTopBar(
    title = "我是标题",
    onBackClick = { /* 返回 */ },
    rightContent = {
        Text("提交", color = Color.Blue, modifier = Modifier.clickable { /* 提交 */ })
    }
)

场景 4:右侧带图标(如搜索或收藏)

适合资讯详情页或列表页:

Kotlin 复制代码
CommonTopBar(
    title = "文章详情",
    onBackClick = { /* 返回 */ },
    rightContent = {
        Icon(
            imageVector = Icons.Default.Favorite, 
            contentDescription = "收藏", 
            tint = Color.Red
        )
    }
)

场景 5:完全自定义的主题颜色

某些特定页面可能需要红色沉浸式背景搭配白色字体:

Kotlin 复制代码
CommonTopBar(
    title = "我是标题",
    onBackClick = { /* 返回 */ },
    backgroundColor = Color.Red,
    titleColor = Color.White
)

总结

在传统的 Android View 系统中,为了实现这么一个高度定制化的标题栏,往往需要写冗长的 XML 布局,使用各种 RelativeLayout 约束,还要在 Activity 中通过 findViewById 动态控制各种 View.GONE

而在 Jetpack Compose 中,得益于声明式 UI 和 Kotlin 强大的 ** 高阶函数(Slot API**支持,不到 60 行代码,我们就构建出了一个极其优雅、灵活且可复用的 CommonTopBar 组件。这也是现代 Android 开发的魅力所在:让 UI 回归逻辑,让封装变得轻盈!

相关推荐
我命由我123458 小时前
执行 Gradle 指令报错,无法将“grep”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
狂奔solar9 小时前
ARMA 模型:从白噪声到万能逼近器
android
渣渣灰飞9 小时前
MySQL 系统学习 第五阶段:企业级 MySQL 实战开发 第二章:RBAC 权限系统设计
android·学习·mysql
qq_4228286210 小时前
android 图形学之图层数据送显及合成图层(七)
android
MiyamuraMiyako11 小时前
Compose:从自动滚动到双锚点 LazyLayout
android·android jetpack
用户634214199350713 小时前
base_logger_core --- 跨平台 C++ 日志核心库
android
苦瓜花13 小时前
【Kotlin】初入门
android·开发语言·kotlin
dora13 小时前
使用 Cling 实现 DLNA 投屏:从局域网发现到媒体播放控制
android·android things·tvos
apihz14 小时前
全球域名 WHOIS 信息实时查询免费 API 接口教程,支持1000+后缀
android·网络·网络协议·tcp/ip·apache·域名·whois
非典型Android程序员16 小时前
Binder机制学习总结
android