HarmonyOS鸿蒙Next中使用splice删除元素后translate动画不能正常显示,找到解决方法,但是不懂原理
HarmonyOS鸿蒙Next中使用splice删除元素后translate动画不能正常显示,找到解决方法,但是不懂原理 使用splice删除元素是默认有动画的吗?看文档找资料试了一晚上,终于测试出来让translate动画能正常显示的方法,看代码吧。
Coord implements TranslateOptions {
x: number
y: number
constructor(x?: number, y?: number) {
this.x = x ? x : 0
this.y = y ? y : 0
}
}
@ObservedV2
class Menuitem {
id: string
index: number
@Trace coord: Coord = new Coord()
constructor(index: number) {
this.index = index
this.id = new Date().getTime().toString()
}
}
@Entry
@ComponentV2
struct Index {
@Local menu: Array<Menuitem> = new Array<Menuitem>()
radiusB = 100
build() {
Column() {
Button('添加图标')
.width(200)
.height(100)
.fontSize(30)
.onClick(() => {
this.menu.push(new Menuitem(this.menu.length))
})
Button('删除图标')
.width(200)
.height(100)
.fontSize(30)
.onClick(() => {
// 无动画,图标瞬移
// this.menu.splice(1, 1)
// for (const m of this.menu) {
// m.coord = new Coord(m.coord.x + 100, 0)
// }
// 删除索引位置后的图标瞬移+残影
// this.menu.splice(1, 1)
// this.getUIContext()?.animateTo({
// duration: 300
// }, () => {
// for (const m of this.menu) {
// m.coord = new Coord(m.coord.x + 100, 0)
// }
// })
// 这个可以正常显示,但是不理解原理
this.getUIContext()?.animateTo({
duration: 0,
onFinish: () => {
this.getUIContext()?.animateTo({
duration: 300
}, () => {
for (const m of this.menu) {
m.coord = new Coord(m.coord.x + 100, 0)
}
})
}
}, () => {
this.menu.splice(1, 1)
})
})
ForEach(this.menu, (item: Menuitem, index: number) => {
Stack() {
Image($r('app.media.startIcon'))
.width(this.radiusB)
.height(this.radiusB)
.borderRadius(this.radiusB)
.draggable(false)
// .syncLoad(true) // 加载尺寸较小的本地图片时开启,解决ForEach加载UI导致图片闪烁的问题
Text(item.index.toString()).fontSize(50)
}
.translate({ x: item.coord.x, y: item.coord.y })
}, (item: Menuitem) => item.id)
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Start)
}
}
更多关于HarmonyOS鸿蒙Next中使用splice删除元素后translate动画不能正常显示,找到解决方法,但是不懂原理的实战教程也可以访问 https://www.itying.com/category-93-b0.html
现象本质
1 直接删除的瞬移问题:直接调用this.menu.splice(1, 1)会导致UI同步更新,但未在动画闭包内操作,系统无法感知状态变化的上下文,因此无法应用动画过渡效果。
2 单层animateTo的残影问题:虽然通过动画闭包执行了坐标修改,但删除操作在闭包外执行,导致两个操作未在同一动画事务中(删除元素与坐标修改分离),界面渲染不同步。
3 双层animateTo的解决方案:通过duration: 0的动画强制同步状态更新,再执行真实动画,确保删除操作与坐标修改在同一事务周期内完成。
动画触发机制原理
1 animateTo的事务性:系统通过动画闭包收集所有状态变更,统一计算过渡效果。未包裹在闭包内的操作会直接生效,导致动画缺失。
2 同步屏障作用:duration: 0的animateTo会立即同步执行闭包内的操作,相当于设置同步屏障,确保后续动画的起始状态正确。
3 ForEach的响应式更新:@ObservedV2类配合ForEach能自动追踪数组变化,但动画需要明确的状态修改边界。嵌套animateTo将删除和坐标修改整合到不同阶段的动画事务中。
代码解读
// 第一层:强制同步删除操作
animateTo({ duration: 0 }, () => {
this.menu.splice(1, 1) // 立即生效的删除操作
})
// 第二层:执行坐标动画
animateTo({ duration: 300 }, () => {
for (const m of this.menu) {
m.coord = new Coord(m.coord.x + 100, 0) // 动画化的坐标修改
}
})
这种分层处理可以确保删除操作立即完成且界面同步更新(通过首层animateTo);剩余元素的坐标修改作为独立动画执行(通过第二层animateTo)
更多关于HarmonyOS鸿蒙Next中使用splice删除元素后translate动画不能正常显示,找到解决方法,但是不懂原理的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
ArkUI的动画系统需要感知组件状态变化才能触发动画。直接调用splice删除数组元素属于非响应式操作(即使使用@ObservedV2),系统无法自动捕获删除动作与后续坐标变化的关联性
当直接使用splice删除元素后立即修改其他元素坐标时,系统会将这两个操作视为同一帧内的状态突变。此时动画系统无法区分哪些属性需要应用过渡效果,导致残影或瞬移。
通过嵌套animateTo强制分步处理
// 第一步:在0ms动画中执行删除
animateTo({ duration: 0 }, () => {
this.menu.splice(1, 1); // 触发ForEach重新渲染
});
// 第二步:在300ms动画中执行坐标变化
animateTo({ duration: 300 }, () => {
for (const m of this.menu) {
m.coord = new Coord(m.coord.x + 100, 0); // 触发translate动画
}
});
在HarmonyOS Next中,splice删除元素后translate动画异常,通常与ArkUI的声明式UI机制有关。splice直接操作数据可能导致UI未及时响应数据变化,动画状态未正确重置。解决方法可能是通过状态管理或强制UI刷新来触发动画更新,确保数据变更与动画帧同步。具体原理涉及ArkUI渲染管线对数据响应和动画状态的处理机制。
在HarmonyOS Next中,使用splice
删除数组元素本身不会触发动画。动画的显示依赖于ArkUI的响应式更新机制和动画帧的同步。
你的解决方案通过嵌套animateTo
来分步处理删除和坐标更新,其原理如下:
-
外层animateTo(duration: 0):立即执行删除操作(splice),此时UI会同步更新,但由于duration为0,不会产生动画效果,只是强制UI重新渲染。
-
内层animateTo(duration: 300):在删除完成后,通过回调触发坐标更新。由于此时UI已经基于新的数组状态渲染,再应用translate动画时,系统能够正确识别元素位置变化,从而平滑执行动画。
这种方法避免了直接删除后立即更新坐标导致的渲染冲突,确保了动画帧与数据状态的同步。