项目地址:GitHub
在这个 AI 大模型满天飞的时代,谁不想拥有一个属于自己的 AI 助手呢?今天,我们就以 ChatDemo 为例,看看如何用一套 Kotlin 代码,在 Android、iOS 和 HarmonyOS 三端上通过 Kuikly Compose 完美复刻 ChatGPT 的流式对话体验。
别被 AI 的高大上吓跑了,其实拆解下来,核心逻辑就像搭积木一样简单。准备好了吗?发车!
页面结构分析
打开 ChatDemo.kt,我们仿佛看到了一位身材曼妙的"美女"------哦不,是一段结构清晰的代码。整个聊天页面 (ChatScreen) 主要由三部分组成:
-
顶部导航栏 (NavBar):展示标题和返回按钮,雷打不动的"天灵盖"。
-
聊天内容区 (MessageList):显示对话流,这是核心的"躯干"。
-
底部输入区 (InputArea):输入框和发送按钮,负责交互的"四肢"。
这种结构在 Kuikly Compose 中实现起来异常清爽,简直就是"所见即所得":
kotlin
// 伪代码结构演示
Box(modifier = Modifier.fillMaxSize()) {
Column {
NavBar() // 1. 天灵盖
ChatList() // 2. 躯干
InputArea() // 3. 四肢
}
}
Kuikly Compose 写法
页面定义
不同于之前的 BasePager + DSL,Compose 风格的页面继承自 ComposeContainer,通过 setContent 开启 Compose 的世界:
kotlin
@Page("ChatDemo")
internal class ChatDemo : ComposeContainer() {
override fun willInit() {
super.willInit()
setContent {
ChatScreen() // 进入 Compose 的声明式 UI 世界
}
}
}
简单粗暴,直接入题!
组件与布局
Kuikly Compose 完美复刻了 Jetpack Compose 的开发体验,让习惯了 Android 开发的同学们倍感亲切。
1. 列表组件 (LazyColumn)
聊天记录怎么展示?LazyColumn 也就是我们常说的 RecyclerView 的"升级版"。
kotlin
LazyColumn(
state = listState,
modifier = Modifier.weight(1f)
) {
itemsIndexed(chatList) { index, message ->
// 根据 index 判断是用户还是 AI,渲染不同的气泡
ChatMessageItem(message, isUser = (index % 2 == 0))
}
}
看到没?没有 Adapter,没有 ViewHolder,就是一个简单的 Lambda,数据驱动 UI,清爽!
2. 输入框 (TextField)
底部的输入框使用了 TextField,这里有一个亮点------键盘避让。Kuikly 贴心地提供了 keyboardHeightChange 修饰符:
kotlin
TextField(
modifier = Modifier
.keyboardHeightChange {
// 键盘弹起时,自动调整高度,避免遮挡输入框
keyboardHeight = it.height
}
)
这行代码一加,键盘弹起时的页面抖动、遮挡问题统统不见,丝般顺滑。
样式与修饰符 (Modifier)
在 Kuikly Compose 中,attr {} 变成了更强大的 Modifier 链式调用。比如首页那个好看的渐变色卡片:
kotlin
Box(
modifier = Modifier
.clip(RoundedCornerShape(16.dp)) // 裁个圆角
.background(
// 来个渐变色
Brush.horizontalGradient(listOf(box.startColor, box.endColor))
)
.clickable { ... } // 加个点击事件
)
这就是声明式 UI 的魅力,你要什么效果,直接往上"叠"就行了。
核心黑科技:跨平台流式响应
界面画好了,怎么让 AI "动"起来?ChatDemo 的核心在于流式响应 (SSE),也就是那个酷炫的"打字机"效果。这里展示了 Kuikly 强大的跨平台能力。
Android & iOS (Ktor 协程)
这两兄弟关系好,直接用 Kotlin 协程配合 Ktor 网络库,处理起来行云流水:
kotlin
// ChatDemo.kt
val channel = response.bodyAsChannel()
while (!channel.isClosedForRead) {
val line = channel.readUTF8Line()
if (line.startsWith("data:")) {
// 收到数据,更新 UI
withContext(Dispatchers.Main) {
chatList[msgIndex] += delta // 界面自动刷新
}
}
}
HarmonyOS (Native Module 桥接)
鸿蒙这位新朋友,Kuikly 也有妙招。在第三方组件Ktor还未完善对鸿蒙的支持情况下,Kuikly提供了Module 桥接机制,99% 的代码用 KMP 共享,剩下 1% 搞不定的平台特性,通过 Module 轻松桥接原生能力。通过 OhosStreamRequestModule,我们能轻松调用鸿蒙原生的 ArkTS 能力:
kotlin
// OhosStreamRequestModule.kt
fun request(...) {
// 呼叫鸿蒙原生层:帮我发个请求!
toNative(true, "request", params) { retEvent ->
// 原生层收到 SSE 数据,回传给 Kotlin
callbackFn.invoke(eventObj)
}
}
这就是 Kuikly 的哲学:能通用的通用,不能通用的桥接。一套架构,搞定所有平台。
细节打磨:Markdown 渲染
AI 返回的代码块、加粗字体怎么显示?直接塞进 Text 肯定不行。Kuikly 提供了 Markdown 组件:
kotlin
Markdown(
state = markdownState,
colors = markdownColor(text = Color.Black), // 定制颜色
typography = markdownTypography() // 定制排版
)
它能实时解析流式传输过来的 Markdown 文本,渲染过程毫无闪烁,稳如老狗。
总结
通过 Review ChatDemo 的源码,我们不仅学会了如何画界面,更解锁了 AI 应用开发的核心技能:
-
Compose 写法:用
Modifier和声明式组件构建 UI,效率起飞。 -
状态管理:
mutableState让数据驱动界面更新,告别繁琐的setText。 -
跨平台架构:Ktor 处理标准平台,Module 桥接新兴平台(鸿蒙),游刃有余。
Kuikly 已经把"地基"打好了,剩下的就看你们如何在上面盖出万丈高楼了!今天的代码 Review 就到这里,还不快去 Clone 下来跑一跑?