当前位置: 首页 > news >正文

前沿探索之Kuikly框架

认识并上手Kuikly

  • 〇、前言
  • 一、UI 描述
  • 二、UI 更新
  • 三、路由跳转与路由传参
    • 1、Module 机制
    • 2、RouterModule
  • 四、生命周期
    • 1、页面的生命周期
    • 2、组件的生命周期
  • 五、总结

〇、前言

最近,腾讯公司开源了一款名为Kuikly跨端开发框架,利用 Kotlin MultiPlatform(KMP) 的跨平台能力构建通用的跨平台 UI 渲染接口。代码风格遵循函数式编程,支持链式调用但不是主要风格。

虽然,也是使用 Kotlin 作为编程语言,但与安卓原生的 Jetpack Compose 的风格,有着明显的区别。在 UI 实现上,个人认为,Kuikly 在一定程度上借鉴了 Flutter。

下面就一起对 Kuikly 进行体系化认识和实践掌握。

一、UI 描述

首先,看一下 Kuikly 框架如何进行页面 UI 的描述,至于环境的搭建,还请参考官方文档:Kuikly环境搭建,这里就不再介绍这种很基础的实践操作了。

Kuikly 框架采用如下的代码结构进行页面UI的描述:

@Page("TestPage", supportInLocal = true)
internal class TestPage: Pager() {override fun body(): ViewBuilder {return {View { attr { allCenter()marginTop(pagerData.statusBarHeight)backgroundColor(Color.BLACK)// ......}Text { attr { fontSize(20f)text("text")}event { click { // ......}}}}}}
}

从如上的代码片段中,不难看出 Kuikly 框架使用 Kotlin 类作为 UI 实现载体,并且通过注解 Page 去声明当前页面的路由名。每个 UI 类都必须直接或间接的继承 Pager 类,并且必须重写 body 方法,而 body 方法返回的就是页面 UI 描述;由于 Kuikly 框架遵循了 Kotlin 的语法,所以,body 方法一次性只能返回一个值,一般就是 ViewContainer<*,*> 对象。

Kuikly 框架弱化了链式调用,为了将组件的样式属性和事件属性彻底区分开来。在 Kuikly 组件中,样式属性集中放在 attr 闭包中,而事件属性则放在 event 闭包中,之所以能够如此,是因为每个组件在实现时都是按照如下结构进行的:
在这里插入图片描述
而后,子组件放在 attr 闭包和 event 闭包之外,子组件的子组件也是如此进行。

这样的结构,无疑让代码变得更加清爽了。

当前,Kuikly 框架内置了如下的典型的UI常用组件:
在这里插入图片描述
基于这些,我们足以组合出更为复杂的自定义组件了。

二、UI 更新

Kuikly 框架中,UI 动态更新跟 Jetpack Compose 一样,都需要借助观察者变量去实现:
在这里插入图片描述
这些观察者变量,通常集中声明为类成员字段,那么,在 body 的返回闭包中,该如何使用呢?答案是在 body 方法里持有 this 实例:
在这里插入图片描述
在 this 里面,可以获取到当前页面的上下文信息 pagerData:
在这里插入图片描述
其中比较关键的就是 param 字段,因为 param 字段记录了外部传入的数据,下面介绍路由传参时会进行讲解。

三、路由跳转与路由传参

1、Module 机制

Kuikly 框架的路由跳转能力,是由目标平台的原生 API 提供的。为了方便开发者,Kuikly 提供了具有忽略目标平台原生API差异的统一接口模块,Module,而获取相应 Module 实例的方式有如下两种:

// 1. 通过acquireModule<T>(moduleName)获取Module, 如果找不到Module的话会抛异常
val cacheModule = acquireModule<[ModuleName]>([ModuleName].MODULE_NAME)// 2. getModule<T>(moduleName)获取Module, 如果找不到Module的话返回null
val cacheModule1 = getModule<[ModuleName]>([ModuleName].MODULE_NAME)

而当前,Kuikly 框架内置实现的 Module 有如下:
在这里插入图片描述
如果上述 Module 无法满足开发需求,那么可以自行扩展原生 API,具体参考Kuikly扩展原生API

2、RouterModule

在 Kuikly 框架内置实现的 Module 中,有一个名为 RouterModle 的,而它正是为 Kuikly 页面提供路由能力的。RouterModule 一共包含两个 API 方法:
在这里插入图片描述
对应的使用方式如下:

  • 打开页面:acquireModule<RouterModule>(RouterModule.MODULE_NAME).openPage(pageName, pageData)
  • 关闭页面:acquireModule<RouterModule>(RouterModule.MODULE_NAME).closePage()

打开页面的方法,是支持携带路由参数到目标页面的,写入参数可以参考如下代码:

private fun jumpPage(inputText: String, extData:  JSONObject? = null) {val params = urlParams("pageName=$inputText")val pageData = JSONObject()params.forEach {pageData.put(it.key, it.value)}if (extData != null){pageData.put("extData", extData)}val pageName = pageData.optString("pageName")acquireModule<RouterModule>(RouterModule.MODULE_NAME).openPage(pageName, pageData)
}
val params = JSONObject()
params.put("data", "测试参数透传")
ctx.jumpPage(ctx.inputText, extData = params)

而读取参数就是从 pagerData 的 param 字段里面读取:

override fun created() {list.add("isAndroid: " + pagerData.isAndroid)list.add("isIOS: " + pagerData.isIOS)super.created()val extData = pagerData.params.optJSONObject("extData")if (extData != null) {val data = extData.optString("data")params = data}
}

不同类型的路由参数,使用不同的 opt… 方法读取,写入也是如此:
在这里插入图片描述

四、生命周期

Kuikly 框架中,生命周期也区分页面级和组件级。

1、页面的生命周期

对于页面的生命周期,可以用如下图进行概述:
在这里插入图片描述

  • created: Pager已经创建, 可以在此方法内进行初始化和数据拉取操作, 此方法会在body方法前调用
  • pageDidAppear: Pager在屏幕上可见, 可以在此方法做一些页面可见性的操作
  • pageDidDisappear: Pager不可见
  • pageWillDestroy: 页面即将销毁,可以在此方法内做一些释放工作,pageWillDestroy回调函数中无法通过Module调用Native方法,如有需要可以考虑在原生侧的生命周期函数中调用

2、组件的生命周期

在Kuikly中,组合组件ComposeView的生命周期如下:

  1. created: ComposeView已经创建, 此方法会在body方法前调用
  2. viewWillLoad: ComposeView的UI组件树即将创建, 此方法会在body方法前调用
  3. viewDidLoad: ComposeView的UI组件树已经创建好, 此方法会在body方法之后调用
  4. viewDidLayout: ComposeView的UI组件树已经测量完毕,可以在此方法执行一些依赖组件大小的操作,例如开始启动动画
  5. viewWillUnload: ComposeView即将被移除
  6. viewDidUnload: ComposeView已经被移除
  7. viewDestroyed: ComposeView已经被销毁

五、总结

如果你认真地跟着本文,将 Kuikly 框架的 UI 描述与更新、Module 机制和生命周期的使用方式掌握,那么,基本上就已经完成了对 Kuikly 的上手,足够用 Kuikly 框架去进行基本APP开发了。

http://www.xdnf.cn/news/634879.html

相关文章:

  • Java 虚拟机(JVM)原理与实战:打造高效稳定的运行环境
  • YOLOV8涨点技巧之空间通道协作注意力(SCCA)-应用于自动驾驶领域
  • 【公式】MathType公式右编号对齐
  • C/C++ 结构体:. 与 -> 的区别与用法及其STM32中的使用
  • 2025.5.25总结
  • Windows 11 [close recent file browsing history]
  • 对WireShark 中的UDP抓包数据进行解析
  • win11 禁用/恢复 内置笔记本键盘(保证管用)
  • 嵌入式软件--DAY8 IIC通讯下 硬件实现
  • 解决WPF短暂的白色闪烁(白色闪屏)
  • 从智能提效到产品赋能的架构实践
  • Pycharm and Flask 的学习心得(9)
  • PCB 通孔是电容性的,但不一定是电容器
  • CSS相关知识
  • 基于PyTorch的残差网络图像分类实现指南
  • 如何理解Pytorch中前向传播的计算过程
  • 小土堆pytorch--神经网络搭建小实战Sequential的使用
  • 高可用 Redis 服务架构分析与搭建
  • 【C/C++】从零开始掌握Kafka
  • P2676 [USACO07DEC] Bookshelf B
  • 电商小程序店铺详情页:头部无限分类与筛选功能实现
  • LabVIEW实战项目推荐与学习建议
  • 打卡第28天:装饰器
  • 【HarmonyOS5】DevEco Studio 预览器与模拟工具详解
  • 掌握聚合函数:COUNT,MAX,MIN,SUM,AVG,GROUP BY和HAVING子句的用法,Where和HAVING的区别
  • TIGER - 一个轻量高效的语音分离模型,支持人声伴奏分离、音频说话人分离等 支持50系显卡 本地一键整合包下载
  • 【Android】非System用户下Persist应用不自动拉起
  • 破解C/C++内存分配与管理:内存对象模型硬核剖析
  • LeetCode-图论-岛屿数量+腐烂的橘子
  • Leetcode 3103. 查找热门话题标签 II