HarmonyOS鸿蒙Next中播放lottie动画,连续播放的时候为啥不连续,会出现空白
HarmonyOS鸿蒙Next中播放lottie动画,连续播放的时候为啥不连续,会出现空白
Canvas(this.mainCanvasRenderingContext)
.width('100%')
.height('100%')
.backgroundColor(Color.Transparent)
.margin(0)
.padding(0)
.onReady(() => {
// 抗锯齿设置
this.mainCanvasRenderingContext.imageSmoothingEnabled = true;
this.mainCanvasRenderingContext.imageSmoothingQuality = 'medium';
// Lottie动画初始化
this.animationItem = lottie.loadAnimation({
container: this.mainCanvasRenderingContext,
renderer: 'canvas',
loop: true,
autoplay: true,
frameRate: 30,
path: this.path,
contentMode: 'Contain',
initialSegment: [0, 200]
});
// 监听每一帧,记录当前帧
this.animationItem.addEventListener('enterFrame', () => {
if (this.animationItem) {
this.currentFrame = Math.floor(this.animationItem.currentFrame);
}
});
})
.onDisAppear(() => {
lottie.destroy();
})
更多关于HarmonyOS鸿蒙Next中播放lottie动画,连续播放的时候为啥不连续,会出现空白的实战教程也可以访问 https://www.itying.com/category-93-b0.html
尊敬的开发者您好!
动画播放过程中出现闪烁现象,由于存在lottie动画切换,怀疑是动画切换导致的闪烁问题。通过修改代码,使得上锁过程一次播放一个动画,可以发现并无闪烁现象,因此需要继续分析动画切换为何导致闪烁,主要排查以下方面:
- 动画切换时的资源加载和销毁。lottie从2.0.15版本开始,lottie动画的Canvas渲染模式每次只能加载一个动画,加载新动画时会自动清理旧动画资源,动画资源加载和清理有可能会导致动画播放的间隔;
- 动画加载和播放的时机。lottie动画分为加载和播放两个阶段,如果切换第二个动画时才进行动画加载,也可能导致动画播放的间隔。
【分析结论】
- lottie2.0.15动画的Canvas渲染模式每次只能加载一个动画,动画切换时,会清理动画资源后再加载播放第二个动画,导致动画播放出现间隔;
- 两个动画依次进行加载并播放,动画切换时,动画加载耗时导致动画播放出现间隔。
【修改建议】
- lottie版本降低至2.0.14或更早版本(不推荐);
- 多Canvas分层架构,即一个lottie动画使用一个Canvas加载(推荐方案)。
- 使用一个Canvas加载一个lottie动画,避免动画切换时进行资源清理;
- 在Canvas的onready中并行加载两个动画,在第一个动画播放完成后再启动第二个动画播放,避免动画切换时加载动画耗时。
针对问题代码,修改示例如下。经验证,修改后动画切换时无闪烁问题。
import lottie, { AnimationItem } from '@ohos/lottie';
@Entry
@Component
struct Index {
private startSettings: RenderingContextSettings = new RenderingContextSettings(true);
private startRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.startSettings);
private loadSettings: RenderingContextSettings = new RenderingContextSettings(true);
private loadRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.loadSettings);
private timerId: number;
private directionFlag: boolean;
animateItemStart: AnimationItem = {} as AnimationItem
animateItemEnd: AnimationItem = {} as AnimationItem
@State isStopMove: boolean = false
@State isStatic: boolean = true // 中间的锁开关是否是静态图
@State isConvas: boolean = false;
loadStartAnimation(mPath?: string, mName?: string, isLoop: boolean = false, afterPlayCallback?: (() => void) | null,
completeCallback?: (() => void) | null) {
this.animateItemStart = lottie.loadAnimation({
container: this.startRenderingContext,
renderer: 'Canvas',
frameRate: 60, // 设置animator的刷帧率为30
loop: isLoop,
autoplay: false,
name: mName,
path: mPath,
});
this.animateItemStart.addEventListener('DOMLoaded', () => {
this.animateItemStart.play()
if (afterPlayCallback) {
afterPlayCallback()
}
})
this.animateItemStart.addEventListener('complete', () => {
if (completeCallback) {
completeCallback()
}
})
}
loadLoadAnimation(mPath?: string, mName?: string, isLoop: boolean = false, afterPlayCallback?: (() => void) | null,
completeCallback?: (() => void) | null) {
this.animateItemEnd = lottie.loadAnimation({
container: this.loadRenderingContext,
renderer: 'Canvas',
frameRate: 60, // 设置animator的刷帧率为30
loop: isLoop,
autoplay: false,
name: mName,
path: mPath,
});
this.animateItemEnd.addEventListener('DOMLoaded', () => {
if (afterPlayCallback) {
afterPlayCallback()
}
})
this.animateItemEnd.addEventListener('complete', () => {
if (completeCallback) {
completeCallback()
}
})
}
onChangeRight() {}
onChangeLeft() {}
build() {
Stack() {
Canvas(this.loadRenderingContext)
.width(60)
.height(60)
.borderRadius(40)
.backgroundColor($r('app.color.color_F7F7F7'))
.onReady(() => {
// 抗锯齿的设置
this.loadRenderingContext.imageSmoothingEnabled = true;
this.loadRenderingContext.imageSmoothingQuality = 'medium'
this.loadLoadAnimation("common/lottie/loading.json", 'loading', false, () => {
clearTimeout(this.timerId)
// 请求接口,成功了回复静态图
this.timerId = setTimeout(() => {
this.isConvas = false
this.isStopMove = false
this.isStatic = true
if (this.directionFlag) {
this.onChangeRight()
} else {
this.onChangeLeft()
}
}, 2000)
})
})
.visibility(this.isStatic ? Visibility.None : Visibility.Visible)
.onDisAppear(() => {
// 组件移除时,可销毁动画资源
lottie.destroy('loading');
})
Canvas(this.startRenderingContext)
.width(60)
.height(60)
.borderRadius(40)
.backgroundColor($r('app.color.color_F7F7F7'))
.onReady(() => {
// 抗锯齿的设置
this.startRenderingContext.imageSmoothingEnabled = true;
this.startRenderingContext.imageSmoothingQuality = 'medium'
this.loadStartAnimation('common/lottie/data.json', 'start', false, () => {
this.isStopMove = true
}, () => {
this.isStatic = false;
this.isConvas = true;
this.animateItemEnd.play();
})
})
.visibility((!this.isStatic && !this.isConvas) ? Visibility.Visible : Visibility.None)
.onDisAppear(() => {
// 组件移除时,可销毁动画资源
lottie.destroy('start');
})
Image($r('app.media.home_clock_static'))
.width(60)
.aspectRatio(1)
.height(60)
.borderRadius(40)
.visibility(this.isStatic ? Visibility.Visible : Visibility.Hidden)
}
}
}
更多关于HarmonyOS鸿蒙Next中播放lottie动画,连续播放的时候为啥不连续,会出现空白的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
我的问题是一个动画资源循环播放,第一次播放完成,播放第二次的时候,中间会出现空白,initialSegment: [0, 200] 这个值无论设置都会出现空白。
尊敬的开发者您好! lottie2.0.28版本,使用中心仓提供的代码未复现。 https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Flottie 还烦请您提供可复现的demo或代码,以及对应的动画json。

试试
试过了,还是不能够连续播放,会出现空白,
开发者您好!您看看二楼的答复是否能够解决您的问题呢?
在HarmonyOS Next中,Lottie动画连续播放出现空白帧,通常是因为动画资源未预加载或播放间隔导致渲染延迟。可检查是否在动画完成回调中立即重启播放,确保使用setRepeatCount设置无限循环而非手动重播。同时确认Lottie版本与HarmonyOS兼容,避免解码耗时引发断层。
在HarmonyOS Next中,Lottie动画播放出现不连续和空白帧,通常与以下几个核心机制有关:
-
Canvas渲染与帧率同步问题:
Canvas的onReady回调触发时,渲染上下文可能尚未完全就绪。当loop: true且autoplay: true时,Lottie动画会立即开始播放。若Canvas渲染线程与动画帧率(frameRate: 30)未完全同步,可能导致首帧或循环衔接帧绘制延迟,出现短暂空白。可尝试在onReady中延迟少量时间(如setTimeout)再启动动画,或确保Canvas尺寸和上下文完全稳定后加载。 -
initialSegment设置与循环冲突:代码中
initialSegment: [0, 200]指定了初始播放片段,但Lottie在循环播放时,若片段结束帧(200)与动画总帧数不匹配,或循环重置时帧索引计算有误差,可能造成片段跳转不连贯。建议检查动画总帧数,并确认initialSegment的结束帧是否合理。可尝试不设置initialSegment,或通过animationItem.playSegments([0,200], true)在加载后控制循环。 -
资源释放与重绘时机:
onDisAppear中调用lottie.destroy()会销毁动画实例,但若组件快速重新出现(如页面切换),新动画加载可能延迟。同时,Canvas在HarmonyOS Next中依赖GPU渲染管线,若动画帧率(30fps)与设备屏幕刷新率(通常60Hz或更高)不匹配,可能丢帧。可考虑将frameRate调整为60,或使用requestAnimationFrame同步。 -
内存与渲染上下文状态:
Canvas的imageSmoothingEnabled等设置可能影响绘制效率。若动画资源较大,连续播放时内存回收或上下文重置可能导致帧丢失。建议监控animationItem.currentFrame在循环点的跳变情况,并确保backgroundColor(Color.Transparent)不引发额外重绘开销。
调试建议:
- 在
enterFrame事件中打印currentFrame,观察循环点(如200帧附近)是否出现非连续值。 - 尝试将
renderer改为'svg'(若支持)排除Canvas特定问题。 - 检查Lottie动画JSON文件本身是否包含空白关键帧或资源加载延迟。
以上因素可能单独或叠加导致不连续现象,需结合具体动画数据和运行环境进一步定位。

