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 回归逻辑,让封装变得轻盈!

相关推荐
数智工坊6 小时前
机器人运动控制:采样、优化与学习三大流派深度对比与实战
android·学习·机器人
故渊at8 小时前
第二板块:Android 四大组件标准化学理 | 第八篇:Service 后台执行实体与优先级
android·gitee·service·前台服务·后台服务
会Tk矩阵群控的小木8 小时前
安卓群控系统对于游戏工作室实战教程
android·运维·游戏·adb·开源软件·个人开发
qeen879 小时前
【C++】类与对象之类的默认成员函数(二)
android·c语言·开发语言·c++·笔记·学习
故渊at9 小时前
第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播
android·gitee·broadcast·广播·动态注册·静态注册
JohnnyDeng9410 小时前
【Android】Room 数据库高级用法与性能调优:从查询瓶颈到毫秒级响应
android·性能优化·kotlin·room
zeqinjie10 小时前
Flutter 折叠屏 iPad / 宽屏适配实践
android·前端·flutter
ab_dg_dp10 小时前
Android 17+ 提取 AIDL 生成 Java 文件的实用脚本
android·java·python
Arrom11 小时前
DLNA 渲染端排障实战:从 20s 卡顿到 stale subscriber 的两周追凶之旅
android·java