Jetpack Compose 震动效果实现技巧与玩法大全
时间:2026-08-21 | 作者:火苗实验室 | 阅读:0上周我在公司摸鱼的时候,发现 Github 上有一个开源库叫 Jindong,没错,听起来就是京东!
我一开始还以为自己看错了,京东什么时候开始干这玩意儿了?后面才发现是误会了。
Jindong 是什么
Jindong 为 Compose 跨平台应用(支持 Android 和 iOS)提供了声明式的触觉反馈 DSL。
它基于 Compose 构建,让你能通过简单直观的 API 定义复杂的触觉模式。
该开源库的作者是来自韩国的开发者。“Jindong”[tindoo]()在韩语中意为“振动”。
好朴实无华的库名称,如果是中文名那岂不就是——Zhendong?
当前移动 UI 开发已经成功转向声明式范式,但与硬件 API 的交互,尤其是触觉反馈,仍然主要依赖命令式编程。
所以这个库的初衷,就是让触觉反馈的交互也转向声明范式。
它解决了在 Compose Multiplatform 应用中实现触觉反馈的复杂性。借助 Compose,开发者现在可以将触觉模式以结构化描述的形式进行定义。
也就是说,它提供了一种声明范式的方式调用硬件 API,同时还支持跨平台。
传统震动
先看看传统的命令式方式。
使用标准 Android API 创建波形振动时,需要并行的时序和振幅值数组:
Column(
modifier = Modifier.fillMaxSize(),
) {
Button(onClick = {
val timings = longArrayOf(0, 50, 100, 50, 100, 50)
val amplitudes = intArrayOf(0, 255, 0, 128, 0, 255)
val effect = VibrationEffect.createWa veform(timings, amplitudes, -1)
defaultVibrator.vibrate(effect)
}) {
Text("Vibrate")
}
}
如果你要调整某个节拍的持续时间,就得重新计算数组索引。
更麻烦的是,这种逻辑是平台相关的。iOS 的 Core Haptics 也需要完全不同的代码实现。
声明式
Jindong 把这些底层细节抽象成了一种 DSL。
开发者只需要定义反馈结构,库会负责执行。
先添加权限和依赖
<uses-permission android:name="android.permission.VIBRATE" />
implementation("io.github.compose-jindong:jindong:1.0.0")
再用 DSL 定义震动
var count by remember { mutableIntStateOf(0) }
JindongProvider { // 需要提供一个 JindongProvider
if (count > 0) { // 防止第一次进来就震动
Jindong(count) { // 传入一个 key,当 key 发生变化的时候,就会震动
Sequence {
repeat(3) { // 重复三次震动
Haptic(50.ms, HapticIntensity.STRONG)
Delay(100.ms)
}
}
}
}
}
Column(
modifier = Modifier.fillMaxSize(),
) {
Button(onClick = {
count++
}) {
Text("Vibrate")
}
}
在这里,开发者只需要定义触觉模式,也就是一个重复三次的序列。
至于平台相关的执行细节,库会自己处理。
这种差异不只是语法不同,关键在于谁来控制执行过程。
这也正是旧式 View 写法和新式 Compose 写法的核心差别:
| 命令式思维 | 声明式思维 |
|---|---|
| “先振动 50ms,然后等待 100ms,再振动 50ms” | “我想要一个 50ms-100ms-50ms 的震动模式” |
| “循环三次,中间有延迟,启动震动” | “我想要三次重复” |
声明式编程关注的是定义目标的逻辑和关系,而不是指定如何实现它们。
“描述要做什么,而不是怎么做。”
生命周期管理
在命令式触觉反馈中,生命周期管理是最大的痛点之一。
如果用户在长时间振动模式播放过程中导航离开当前页面,会发生什么?
在命令式编程里,你必须手动在 onPause 或 onDispose 中调用 vibrator.cancel()。
而使用 Jindong 时,触觉模式会自动绑定到 Compose 的生命周期。
- 自动取消:当 Composable 离开组合时,触觉引擎会立即停止。
- 响应式更新:就像
LaunchedEffect一样,如果在模式播放过程中keys发生变化,Jindong 会自动取消当前模式,并根据新状态重新开始执行。
/**
* 当 keys 发生变化时,触发触觉模式执行的可组合函数。
*/
@Composable
fun jindong(
vararg keys: Any,
content: @Composable JindongScope.() -> Unit,
) {
val pattern = rememberHapticPattern(content)
val executor = LocalHapticExecutor.current
LaunchedEffect(*keys) {
executor.execute(pattern)
}
}
这正是 Compose 的一大优势。
你无需特别关心生命周期。
当你离开组合时,当前的副作用会自动结束。
搞点例子
以下是一些 Jindong 的实用场景。
下面的例子因为篇幅我没有显示的指定 JindongProvider,实际上所有的 Jindong 都需要在 JindongProvider 内部。
屏幕进入反馈
使用 Unit 作为触发键,可以在进入屏幕时立即触发热反馈:
@Composable
fun WelcomeScreen() {
// 页面出现时执行一次
Jindong(Unit) {
Haptic(100.ms, HapticIntensity.MEDIUM)
}
}
按钮点击反馈
@Composable
fun TapButton() {
var taps by remember { mutableIntStateOf(0) }
if (taps > 0) {
Jindong(taps) {
Haptic(100.ms, HapticIntensity.LIGHT)
}
}
Button(onClick = { taps++ }) {
Text("Tap")
}
}
淡出效果
@Composable
fun FadeOutHaptic(trigger: Int) {
Jindong(trigger) {
RepeatWithIndex(5) { index ->
val intensity = HapticIntensity.Custom(1.0f - (index * 0.2f))
Haptic(50.ms, intensity)
Delay(100.ms)
}
}
}
模拟心跳
@Composable
fun HeartbeatHaptic(trigger: Int) {
Jindong(trigger) {
Repeat(5) {
// Lub(强脉冲)
Haptic(60.ms, HapticIntensity.STRONG)
Delay(80.ms)
// Dub(弱脉冲)
Haptic(40.ms, HapticIntensity.MEDIUM)
Delay(400.ms)
}
}
}
强烈建议各位试一下,这个特别像!
内部原理:Compose Runtime 与 CMP
Compose Runtime 的作用是什么?
Compose Runtime 是一个与 UI 渲染无关的树管理引擎。
Jindong 依赖于 Compose 运行时的两个核心组件:
- ComposeNode:这是一个通用函数,用于将节点插入到树中。在 Jindong 中,每个 DSL 函数(如
Haptic、Delay和Sequence)都会在内部调用ComposeNode,以创建特定的HapticNode实现。 - Applier:运行时需要知道如何将这些节点连接起来。
Applier负责处理HapticNode树的结构更新,该树会在播放前被遍历,以收集ScheduledHapticEvent事件。
正如 Compose UI 通过构建 LayoutNode 树来渲染像素那样,Jindong 是通过构建 HapticNode 树来合成振动效果的。
这使得我们能够运用标准的 Compose 特性,比如 SideEffect、remember,再结合 Kotlin 的标准控制流,像 if/when/for,自然而然地构建出动态的触觉体验。
Compose Multiplatform 实现
Jindong 遵循标准的 CMP(Compose Multiplatform)架构:
- 通用层(Common Layer) :包含 Compose DSL 定义、节点(Nodes)以及
HapticPattern数据模型。所有时间计算和模式编译都在此层完成,确保跨平台行为的一致性。 - 平台层(Platform Layer,即执行器 Executor) :
- Android:将
HapticPattern转换为VibrationEffect(使用VibrationEffect.createWa veform)。 - iOS:将
HapticPattern转换为CHHapticPattern,用于 Core Haptics。
- Android:将
Android 和 iOS 对振动强度的处理方式不同。
Android 使用振幅整数(1–255),而 iOS 的 Core Haptics 使用归一化的浮点值(0.0–1.0)。
Jindong 提供了一个统一的抽象层。
开发者可以使用归一化的百分比,例如 intensity = 0.5f,来定义强度,无需关心平台特定的数学转换。
总结
Jindong 旨在解决在 Compose Multiplatform 应用中实现触觉反馈的复杂性。
通过利用 Compose 运行时,开发者可以将触觉模式定义为结构化描述,而非一系列电机命令序列。
各位还在等什么,赶紧用起来试试呀!
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 迅捷路由器怎么调信号最强,设置时要注意什么?
- 时间:2026-08-27
-
- vivo浏览器怎么卸不掉?原因和解决方法在这里
- 时间:2026-08-27
-
- OPPO R11s黑屏了,怎么强制恢复出厂设置?
- 时间:2026-08-27
-
- 飞利浦显示器包装盒有生产日期和保修期吗?怎么看?
- 时间:2026-08-27
-
- 联想新平板开机必须联网吗?怎么做?
- 时间:2026-08-27
-
- 平板横竖屏切换设置与问题解决
- 时间:2026-08-27
-
- 移动电源容量怎么测?要准备哪些工具?
- 时间:2026-08-27
-
- 荣耀90 Pro防水吗?防水级别多少?怎么用才安全
- 时间:2026-08-27
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15