emo 0.9.0 来了!

3,803 阅读3分钟

emo 今天往 MavenCentral 上发布了 0.9.0 的版本。

emo.png

依赖更新

这个版本,首先是依赖库的更新:

  1. Compose BOM 升级到 2023.08.00,即依赖 Compose 1.5.0
  2. Compose Compiler 升级到 1.5.2
  3. kotlin 升级到 1.9.0
  4. constraintLayout-compose 使用 1.1.0-alpha10,现在唯有 photo 库用到。
  5. accompanist 升级到 0.32.0

由于 navigation 的动画系统从 accompanist 中转正,所以 scheme 库也移除了 accompanistnavigation-animation 的依赖,转而使用官方 navigation 库,如果使用了自定义的转场动画实现,则需要稍微适配一下,否则对使用者没有影响。

Compose 1.5.0 带来了 mutableIntStateOfmutableLongStateOfmutableFloatStateOfmutableDoubleStateOf 为基础类型服务,emo 也随之更新了所有可以使用的地方。

添加 BOM 支持

由于 emo 的子库众多了,而且相互之间也存在依赖关系, emo 现在也开始使用 BOM 来方便调用者进行版本管理。当前 BOM 版本为 2023.08.00

开发只需要在 build.gradle.ktsdependencies 里添加

implementation(platform("cn.qhplus.emo:bom:2023.08.00"))

就可以去除掉其它 emo 库的版本好了,当然,也有例外。

例外就是我实测 ksp 的依赖并 bom 的管理,所以对于 configschemeksp 还是需要加上版本号。。。

代码重构

对于 photo 库进行了小小的重构,之前写了一份耦合严重,混乱不堪的 GesturePhoto 组件,现在重构了一份 GestureContent 组件,之所以改名,其目前不只是服务于图片预览,而且服务于 pdf 查看,而且开发也可以直接使用,只要用它包裹内容,就拥有了图片预览的常见手势缩放移动操作。

val gestureContentState = remember {
    GestureContentState(
        ratio,
        isLongImage,
    )
}

GestureContent(
    modifier = Modifier.fillMaxSize(),
    state = gestureContentState,
    onTap = {
        ...
    },
    canTransformStart = {
        ...
    },
) { onRatioEnsure ->
    // content
}

现在图片预览组件也基于 GestureContent 了,代码可读性更高,也便于自己之后的维护和修改。

其它主要就是一些自己发现,或者群友们使用过程中发现的大大小小的 bugfix 了。

在升级过程中,有一个有意思的发现:

Compose 1.5.0 将更多的 Modifier 利用 Modifier.Node 这一接口进行了重构,这包括了事件处理的 pointerInput,但这里它有一点小小的不同。

我们知道,pointerInput 提供的 lambda 是在协程中执行的,但是旧版本的实现中,协程是 pointerInput 执行时就启动了,而新版本实现则是首次事件发生时才启动。假设一个界面有 100pointerInput, 那旧版本就会一开始就启动了 100 个协程,而新版本则是触碰了哪个才启动对应的协程,这无疑可以减少协程数量,毕竟不是每个按钮都会被点击。但随之而来也必须注意写法了。

之前我要监听多种手势时,我的写法是下面这样子:

Modifier.pointerInput(Unit){
    launch {
        detectTapGestures(...)
    }

    launch {
        awaitEachGesture(...)
    }
}

我在 pointerInput 里启动多个子协程去监听多个不同的手势处理,但在新版本,因为首次事件发生才会启动协程,而 launch 启动则会造成异步,也就是第一次的事件无法被子协程所捕获,就造成了事件丢失。

所以我们要更换写法,我们可以给 launch 加上 CoroutineStart.UNDISPATCHED 来指明子协程启动完成后才继续执行自身,pointerInput 内部也是用这种方式来保证第一次事件不丢失的。我们也可以分成两个 pointerInput

Modifier.pointerInput(Unit){
    detectTapGestures(...)
}.pointerInput(Unit){
    awaitEachGesture(...)
}

目前我倾向于第二种,因为可以事件处理程序可能依赖不同的 key, 分开是最好的。

最后,官网文档也已经更新!!!


我是古哥E下,前微信读书客户端程序猿 / 自学 5 年中医,维护过上万 Star 开源项目 QMUI Android,现独立维护好用简洁的 Android 组件库 emo

关注我可得:ChatGPT 开发玩法 | 程序员学习经验 | 组件库新变动 | 中医健康调理 。

emo官网:emo.qhplus.cn