ArkUI 帧动画:一帧一帧动,别把它当 GIF 凑合
【摘要】 今天我们用 ImageAnimator 播放一组图片帧。 帧动画适合“我已经有一组连续素材”的场景。比如小插画、状态表情、加载形象。这个 Demo 为了不引入新素材,复用项目里的 startIcon 做四帧位置变化,重点看 ImageFrameInfo 和播放状态。 这个 Demo 看什么 frames 是 Image
ArkUI 帧动画:一帧一帧动,别把它当 GIF 凑合
今天我们用 ImageAnimator 播放一组图片帧。
帧动画适合“我已经有一组连续素材”的场景。比如小插画、状态表情、加载形象。这个 Demo 为了不引入新素材,复用项目里的 startIcon 做四帧位置变化,重点看 ImageFrameInfo 和播放状态。
这个 Demo 看什么
frames 是 ImageFrameInfo[]。每一帧都可以配置:
src:图片资源。width/height:这一帧的尺寸。top/left:这一帧相对动画组件的位置。duration:这一帧停留多久。
ImageAnimator 再通过 images、state、duration、iterations 和 fillMode 控制播放。这里没有使用 @ohos.animator,因为本篇重点是图片帧;如果你要驱动纯数值变化,再考虑数值动画更合适。
你做过最麻烦的帧动画是什么?是素材尺寸不统一,还是循环节奏不自然?这个问题很常见。
完整代码
@Entry
@Component
struct ArkUIFrameAnimationDemo {
@State playStatus: AnimationStatus = AnimationStatus.Running;
private frames: ImageFrameInfo[] = [
{ src: $r('app.media.startIcon'), width: 72, height: 72, top: 42, left: 20, duration: 260 },
{ src: $r('app.media.startIcon'), width: 82, height: 82, top: 32, left: 92, duration: 260 },
{ src: $r('app.media.startIcon'), width: 72, height: 72, top: 48, left: 178, duration: 260 },
{ src: $r('app.media.startIcon'), width: 64, height: 64, top: 58, left: 96, duration: 260 }
];
@Builder
HeaderBlock() {
Column({ space: 8 }) {
Text('ArkUI 帧动画')
.fontSize(28)
.fontWeight(700)
.fontColor('#111827')
Text('一帧一帧动,别把它当 GIF 凑合')
.fontSize(16)
.fontColor('#4B5563')
Text('ImageAnimator 适合播放已经准备好的连续帧。这里复用 startIcon 做四帧位置变化,只看帧动画的基本结构。')
.fontSize(14)
.fontColor('#6B7280')
.lineHeight(22)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
build() {
Scroll() {
Column({ space: 22 }) {
this.HeaderBlock()
Column({ space: 12 }) {
ImageAnimator()
.images(this.frames)
.state(this.playStatus)
.duration(1040)
.iterations(-1)
.fillMode(FillMode.Forwards)
.fixedSize(false)
.width('100%')
.height(180)
.borderRadius(20)
.backgroundColor('#F8FAFC')
.border({ width: 1, color: '#E5E7EB' })
Row({ space: 12 }) {
Button(this.playStatus === AnimationStatus.Running ? '暂停' : '播放')
.height(42)
.fontSize(14)
.fontColor('#FFFFFF')
.backgroundColor('#2563EB')
.borderRadius(21)
.layoutWeight(1)
.onClick(() => {
this.playStatus = this.playStatus === AnimationStatus.Running ? AnimationStatus.Paused : AnimationStatus.Running;
})
Button('回到初始')
.height(42)
.fontSize(14)
.fontColor('#111827')
.backgroundColor('#E5E7EB')
.borderRadius(21)
.layoutWeight(1)
.onClick(() => {
this.playStatus = AnimationStatus.Initial;
})
}
.width('100%')
}
.width('100%')
Column({ space: 8 }) {
Text('ImageAnimator 适合什么')
.fontSize(18)
.fontWeight(700)
.fontColor('#111827')
Text('如果素材已经是一组连续图片,用 ImageAnimator 很直接。如果只是数值从 0 到 100 变化,一般用 animation、animateTo 或 @ohos.animator 这类数值驱动方案更合适。')
.fontSize(14)
.fontColor('#4B5563')
.lineHeight(22)
}
.width('100%')
.padding(16)
.borderRadius(16)
.backgroundColor('#F8FAFC')
.border({ width: 1, color: '#E5E7EB' })
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)