1# ImageAnimator 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @liyujie43--> 5<!--Designer: @weixin_52725220--> 6<!--Tester: @xiong0104--> 7<!--Adviser: @HelloCrease--> 8 9提供帧动画组件来实现逐帧播放图片的能力,可以配置需要播放的图片列表,每张图片可以配置时长。 10 11> **说明:** 12> 13> 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 14 15 16 17## 子组件 18 19无 20 21 22## 接口 23 24ImageAnimator() 25 26**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 27 28**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 29 30**系统能力:** SystemCapability.ArkUI.ArkUI.Full 31 32## 属性 33 34除支持[通用属性](ts-component-general-attributes.md)外,还支持以下属性: 35 36### images 37 38images(value: Array<ImageFrameInfo>) 39 40设置图片帧信息集合。不支持动态更新。 41 42**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 43 44**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 45 46**系统能力:** SystemCapability.ArkUI.ArkUI.Full 47 48**参数:** 49 50| 参数名 | 类型 | 必填 | 说明 | 51| ------ | ------------------------------------------------------ | ---- | ------------------------------------------------------------ | 52| value | Array<[ImageFrameInfo](#imageframeinfo对象说明)> | 是 | 设置图片帧信息集合。每一帧的帧信息(ImageFrameInfo)包含图片路径、图片大小、图片位置和图片播放时长信息,详见[ImageFrameInfo](#imageframeinfo对象说明)对象说明。<br/>默认值:[] <br/> **说明:** 传入数组的内容过大时,内存占用会随之升高。此内存由开发者自行控制。因此,开发者在传入数据前,请充分评估内存消耗情况,以避免内存不足等问题。 | 53 54### state 55 56state(value: AnimationStatus) 57 58控制播放状态。 59 60**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 61 62**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 63 64**系统能力:** SystemCapability.ArkUI.ArkUI.Full 65 66**参数:** 67 68| 参数名 | 类型 | 必填 | 说明 | 69| ------ | ------------------------------------------------------- | ---- | ------------------------------------------------------------ | 70| value | [AnimationStatus](ts-appendix-enums.md#animationstatus) | 是 | 默认为初始状态,用于控制播放状态。<br/>默认值:AnimationStatus.Initial | 71 72### duration 73 74duration(value: number) 75 76设置播放时长。当Images中任意一帧图片设置了单独的duration后,该属性设置无效。 77 78**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 79 80**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 81 82**系统能力:** SystemCapability.ArkUI.ArkUI.Full 83 84**参数:** 85 86| 参数名 | 类型 | 必填 | 说明 | 87| ------ | ------ | ---- | ------------------------------------------------------------ | 88| value | number | 是 | 播放时长。<br/>value为0时,不播放图片。<br/>value平均分配给单张图片的播放时长小于一帧时间,将导致播放异常。<br/>设置为负数时,取默认值。<br/>value的改变只会在下一次循环开始时生效。<br/>单位:毫秒<br/>默认值:1000ms | 89 90### reverse 91 92reverse(value: boolean) 93 94设置播放方向。 95 96**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 97 98**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 99 100**系统能力:** SystemCapability.ArkUI.ArkUI.Full 101 102**参数:** 103 104| 参数名 | 类型 | 必填 | 说明 | 105| ------ | ------- | ---- | ------------------------------------------------------------ | 106| value | boolean | 是 | 播放方向。<br/>false表示从第1张图片播放到最后1张图片,true表示从最后1张图片播放到第1张图片。<br/>默认值:false | 107 108### fixedSize 109 110fixedSize(value: boolean) 111 112设置图片大小是否固定为组件大小。 113 114**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 115 116**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 117 118**系统能力:** SystemCapability.ArkUI.ArkUI.Full 119 120**参数:** 121 122| 参数名 | 类型 | 必填 | 说明 | 123| ------ | ------- | ---- | ------------------------------------------------------------ | 124| value | boolean | 是 | 设置图片大小是否固定为组件大小。 true表示图片大小与组件大小一致,此时设置图片的width 、height 、top 和left属性无效。false表示每一张图片的width 、height 、top和left属性都要单独设置。图片宽高与组件宽高不一致时,图片不会被拉伸。<br/>默认值:true | 125 126### preDecode<sup>(deprecated)</sup> 127 128preDecode(value: number) 129 130设置预解码的图片数量。 131 132从API version 9开始废弃。 133 134**系统能力:** SystemCapability.ArkUI.ArkUI.Full 135 136**参数:** 137 138| 参数名 | 类型 | 必填 | 说明 | 139| ------ | ------ | ---- | ------------------------------------------------------------ | 140| value | number | 是 | 预解码的图片数量。例如,设置为2时,播放当前页时会提前加载后面两张图片至缓存,以提升性能。<br/>默认值:0 | 141 142### fillMode 143 144fillMode(value: FillMode) 145 146设置当前播放方向下,动画开始前和结束后的状态。动画结束后的状态由fillMode和reverse属性共同决定。例如,fillMode为Forwards表示停止时维持动画最后一个关键帧的状态,若reverse为false则维持正播的最后一帧,即最后一张图,若reverse为true则维持逆播的最后一帧,即第一张图。 147 148**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 149 150**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 151 152**系统能力:** SystemCapability.ArkUI.ArkUI.Full 153 154**参数:** 155 156| 参数名 | 类型 | 必填 | 说明 | 157| ------ | ----------------------------------------- | ---- | ------------------------------------------------------------ | 158| value | [FillMode](ts-appendix-enums.md#fillmode) | 是 | 当前播放方向下,动画开始前和结束后的状态。<br/>默认值:FillMode.Forwards | 159 160### iterations 161 162iterations(value: number) 163 164设置播放次数。 165 166**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 167 168**系统能力:** SystemCapability.ArkUI.ArkUI.Full 169 170**参数:** 171 172| 参数名 | 类型 | 必填 | 说明 | 173| ------ | ------ | ---- | ------------------------------------------------------ | 174| value | number | 是 | 默认播放一次,设置为-1时表示无限次播放,设置为小于-1的负数时取默认值。设置为浮点数时,数值向下取整。<br/>默认值:1 | 175 176### monitorInvisibleArea<sup>17+</sup> 177 178monitorInvisibleArea(monitorInvisibleArea: boolean) 179 180设置组件是否通过系统[onVisibleAreaChange](./ts-universal-component-visible-area-change-event.md#onvisibleareachange)的可见性判定,控制组件的暂停和播放。 181 182**原子化服务API:** 从API version 17开始,该接口支持在原子化服务中使用。 183 184**系统能力:** SystemCapability.ArkUI.ArkUI.Full 185 186**参数:** 187 188| 参数名 | 类型 | 必填 | 说明 | 189| ------ | ------ | ---- | ------------------------------------------------------ | 190| monitorInvisibleArea | boolean | 是 | 当设置为true时,组件将基于系统的[onVisibleAreaChange](./ts-universal-component-visible-area-change-event.md#onvisibleareachange)可见性判定,控制组件的暂停和播放。<br/> 当组件的运行状态为[AnimationStatus](ts-appendix-enums.md#animationstatus)的Running时,若判定组件不可见,则自动执行暂停操作;若判定为可见,则自动恢复播放。<br/>默认值:false <br/> **说明:** <br/>当该属性由true动态修改为false时,组件将依据当前的[AnimationStatus](ts-appendix-enums.md#animationstatus)状态进行处理。<br/> 例如,若当前状态为Running且因[onVisibleAreaChange](./ts-universal-component-visible-area-change-event.md#onvisibleareachange)的不可见回调暂停,则在属性由true改为false后,组件会从上次暂停的位置重新开始播放。<br/>由该属性导致的不可见暂停和可见暂停操作不会改变用户设置的[state](./ts-basic-components-imageanimator.md#state)值。| 191 192## ImageFrameInfo对象说明 193 194图片帧信息集合。 195 196**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 197 198**系统能力:** SystemCapability.ArkUI.ArkUI.Full 199 200| 名称 | 类型 | 只读 | 可选 | 说明 | 201| -------- | -------------- | -------- | -------- | -------- | 202| src | string \| [Resource](ts-types.md#resource)<sup>9+</sup> \| [PixelMap](ts-image-common.md#pixelmap)<sup>12+</sup> | 否 | 否 | 图片路径,图片格式为jpg、jpeg、svg、png、bmp、webp、ico和heif,从API Version9开始支持[Resource](ts-types.md#resource)类型的路径,从API version 12开始支持[PixelMap](ts-image-common.md#pixelmap)类型。 <br/>**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。| 203| width | number \| string | 否 | 是 | 图片宽度。string类型支持number类型取值的字符串形式,可以附带单位,例如"2"、"2px"。<br/>默认值:0<br/>单位:vp <br/>**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用 | 204| height | number \| string | 否 | 是 | 图片高度。string类型支持number类型取值的字符串形式,可以附带单位,例如"2"、"2px"。<br/>默认值:0<br/>单位:vp <br/>**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用 | 205| top | number \| string | 否 | 是 | 图片相对于组件左上角的纵向坐标。string类型支持number类型取值的字符串形式,可以附带单位,例如"2"、"2px"。<br/>默认值:0<br/>单位:vp <br/>**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用 | 206| left | number \| string | 否 | 是 | 图片相对于组件左上角的横向坐标。string类型支持number类型取值的字符串形式,可以附带单位,例如"2"、"2px"。<br/>默认值:0<br/>单位:vp <br/>**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用 | 207| duration | number | 否 | 是 | 每帧图片的播放时长,单位毫秒。<br/>默认值:0<br/>不支持负数。设置为负数将导致图片在当前帧长时间停留,影响正常播放。 | 208 209## 事件 210 211除支持[通用事件](ts-component-general-events.md)外,还支持以下事件: 212 213### onStart 214 215onStart(event: () => void) 216 217状态回调,动画开始播放时触发。 218 219**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 220 221**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 222 223**系统能力:** SystemCapability.ArkUI.ArkUI.Full 224 225**参数:** 226 227| 参数名 | 类型 | 必填 | 说明 | 228| -------- | ------------------------------------------ | ---- | -------------------------- | 229| event | () => void | 是 | 状态回调,动画开始播放时触发。 | 230 231### onPause 232 233onPause(event: () => void) 234 235状态回调,动画暂停播放时触发。 236 237**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 238 239**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 240 241**系统能力:** SystemCapability.ArkUI.ArkUI.Full 242 243**参数:** 244 245| 参数名 | 类型 | 必填 | 说明 | 246| -------- | ------------------------------------------ | ---- | -------------------------- | 247| event | () => void | 是 | 状态回调,动画暂停播放时触发。 | 248 249### onRepeat 250 251onRepeat(event: () => void) 252 253状态回调,动画重复播放时触发。 254 255**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 256 257**系统能力:** SystemCapability.ArkUI.ArkUI.Full 258 259**参数:** 260 261| 参数名 | 类型 | 必填 | 说明 | 262| -------- | ------------------------------------------ | ---- | -------------------------- | 263| event | () => void | 是 | 状态回调,动画重复播放时触发。 | 264 265### onCancel 266 267onCancel(event: () => void) 268 269状态回调,动画返回最初状态时触发。 270 271**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 272 273**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 274 275**系统能力:** SystemCapability.ArkUI.ArkUI.Full 276 277 278**参数:** 279 280| 参数名 | 类型 | 必填 | 说明 | 281| -------- | ------------------------------------------ | ---- | -------------------------- | 282| event | () => void | 是 | 状态回调,动画返回最初状态时触发。 | 283 284### onFinish 285 286onFinish(event: () => void) 287 288状态回调,动画播放完成时或者停止播放时触发。 289 290**卡片能力:** 从API version 10开始,该接口支持在ArkTS卡片中使用。 291 292**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 293 294**系统能力:** SystemCapability.ArkUI.ArkUI.Full 295 296**参数:** 297 298| 参数名 | 类型 | 必填 | 说明 | 299| -------- | ------------------------------------------ | ---- | -------------------------- | 300| event | () => void | 是 | 状态回调,动画播放完成时或者停止播放时触发。 | 301 302## 示例 303 304### 示例1(播放Resource动画) 305 306通过ImageAnimator组件播放Resource动画。 307 308```ts 309// xxx.ets 310@Entry 311@Component 312struct ImageAnimatorExample { 313 @State state: AnimationStatus = AnimationStatus.Initial; 314 @State reverse: boolean = false; 315 @State iterations: number = 1; 316 317 build() { 318 Column({ space: 10 }) { 319 ImageAnimator() 320 .images([ 321 { 322 // $r('app.media.img1')需要替换为开发者所需的图像资源文件。 323 src: $r('app.media.img1') 324 }, 325 { 326 // $r('app.media.img2')需要替换为开发者所需的图像资源文件。 327 src: $r('app.media.img2') 328 }, 329 { 330 // $r('app.media.img3')需要替换为开发者所需的图像资源文件。 331 src: $r('app.media.img3') 332 }, 333 { 334 // $r('app.media.img4')需要替换为开发者所需的图像资源文件。 335 src: $r('app.media.img4') 336 } 337 ]) 338 .duration(4000) 339 .state(this.state) 340 .reverse(this.reverse) 341 .fillMode(FillMode.None) 342 .iterations(this.iterations) 343 .width(340) 344 .height(240) 345 .margin({ top: 100 }) 346 .onStart(() => { 347 console.info('Start') 348 }) 349 .onPause(() => { 350 console.info('Pause') 351 }) 352 .onRepeat(() => { 353 console.info('Repeat') 354 }) 355 .onCancel(() => { 356 console.info('Cancel') 357 }) 358 .onFinish(() => { 359 console.info('Finish') 360 this.state = AnimationStatus.Stopped 361 }) 362 Row() { 363 Button('start').width(100).padding(5).onClick(() => { 364 this.state = AnimationStatus.Running 365 }).margin(5) 366 Button('pause').width(100).padding(5).onClick(() => { 367 this.state = AnimationStatus.Paused // 显示当前帧图片 368 }).margin(5) 369 Button('stop').width(100).padding(5).onClick(() => { 370 this.state = AnimationStatus.Stopped // 显示动画的起始帧图片 371 }).margin(5) 372 } 373 374 Row() { 375 Button('reverse').width(100).padding(5).onClick(() => { 376 this.reverse = !this.reverse 377 }).margin(5) 378 Button('once').width(100).padding(5).onClick(() => { 379 this.iterations = 1 380 }).margin(5) 381 Button('infinite').width(100).padding(5).onClick(() => { 382 this.iterations = -1 // 无限循环播放 383 }).margin(5) 384 } 385 }.width('100%').height('100%') 386 } 387} 388``` 389 390 391 392### 示例2(播放PixelMap动画) 393 394通过ImageAnimator组件播放PixelMap动画。 395 396```ts 397// xxx.ets 398import { image } from '@kit.ImageKit'; 399 400@Entry 401@Component 402struct ImageAnimatorExample { 403 imagePixelMap: Array<PixelMap> = []; 404 @State state: AnimationStatus = AnimationStatus.Initial; 405 @State reverse: boolean = false; 406 @State iterations: number = 1; 407 @State images: Array<ImageFrameInfo> = []; 408 409 async aboutToAppear() { 410 // $r('app.media.1')需要替换为开发者所需的图像资源文件。 411 this.imagePixelMap.push(await this.getPixmapFromMedia($r('app.media.1'))); 412 // $r('app.media.2')需要替换为开发者所需的图像资源文件。 413 this.imagePixelMap.push(await this.getPixmapFromMedia($r('app.media.2'))); 414 // $r('app.media.3')需要替换为开发者所需的图像资源文件。 415 this.imagePixelMap.push(await this.getPixmapFromMedia($r('app.media.3'))); 416 // $r('app.media.4')需要替换为开发者所需的图像资源文件。 417 this.imagePixelMap.push(await this.getPixmapFromMedia($r('app.media.4'))); 418 this.images.push({ src: this.imagePixelMap[0] }); 419 this.images.push({ src: this.imagePixelMap[1] }); 420 this.images.push({ src: this.imagePixelMap[2] }); 421 this.images.push({ src: this.imagePixelMap[3] }); 422 } 423 424 build() { 425 Column({ space: 10 }) { 426 ImageAnimator() 427 .images(this.images) 428 .duration(2000) 429 .state(this.state) 430 .reverse(this.reverse) 431 .fillMode(FillMode.None) 432 .iterations(this.iterations) 433 .width(340) 434 .height(240) 435 .margin({ top: 100 }) 436 .onStart(() => { 437 console.info('Start'); 438 }) 439 .onPause(() => { 440 console.info('Pause'); 441 }) 442 .onRepeat(() => { 443 console.info('Repeat'); 444 }) 445 .onCancel(() => { 446 console.info('Cancel'); 447 }) 448 .onFinish(() => { 449 console.info('Finish'); 450 this.state = AnimationStatus.Stopped; 451 }) 452 Row() { 453 Button('start').width(100).padding(5).onClick(() => { 454 this.state = AnimationStatus.Running; 455 }).margin(5) 456 Button('pause').width(100).padding(5).onClick(() => { 457 this.state = AnimationStatus.Paused; // 显示当前帧图片 458 }).margin(5) 459 Button('stop').width(100).padding(5).onClick(() => { 460 this.state = AnimationStatus.Stopped; // 显示动画的起始帧图片 461 }).margin(5) 462 } 463 464 Row() { 465 Button('reverse').width(100).padding(5).onClick(() => { 466 this.reverse = !this.reverse; 467 }).margin(5) 468 Button('once').width(100).padding(5).onClick(() => { 469 this.iterations = 1; 470 }).margin(5) 471 Button('infinite').width(100).padding(5).onClick(() => { 472 this.iterations = -1; // 无限循环播放 473 }).margin(5) 474 } 475 }.width('100%').height('100%') 476 } 477 478 private async getPixmapFromMedia(resource: Resource) { 479 let unit8Array = await this.getUIContext().getHostContext()?.resourceManager?.getMediaContent(resource.id); 480 let imageSource = image.createImageSource(unit8Array?.buffer.slice(0, unit8Array.buffer.byteLength)); 481 let createPixelMap: image.PixelMap = await imageSource.createPixelMap({ 482 desiredPixelFormat: image.PixelMapFormat.RGBA_8888 483 }); 484 await imageSource.release(); 485 return createPixelMap; 486 } 487} 488``` 489 490 491 492### 示例3(设置不可见自动停播) 493 494通过[monitorInvisibleArea](#monitorinvisiblearea17)属性实现了当ImageAnimator的[state](#state)属性为AnimationStatus.Running时,控制组件在不可见时停止播放,在可见时恢复播放。 495 496```ts 497@Entry 498@Component 499struct ImageAnimatorAutoPauseTest { 500 scroller: Scroller = new Scroller(); 501 @State state: AnimationStatus = AnimationStatus.Running; 502 @State reverse: boolean = false; 503 @State iterations: number = 100; 504 @State preCallBack: string = 'Null'; 505 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 506 507 build() { 508 Stack({ alignContent: Alignment.TopStart }) { 509 Scroll(this.scroller) { 510 Column() { 511 ImageAnimator() 512 .images([ 513 { 514 // $r('app.media.Clouds')需要替换为开发者所需的图像资源文件。 515 src: $r('app.media.Clouds') 516 }, 517 { 518 // $r('app.media.landscape')需要替换为开发者所需的图像资源文件。 519 src: $r('app.media.landscape') 520 }, 521 { 522 // $r('app.media.sky')需要替换为开发者所需的图像资源文件。 523 src: $r('app.media.sky') 524 }, 525 { 526 // $r('app.media.mountain')需要替换为开发者所需的图像资源文件。 527 src: $r('app.media.mountain') 528 } 529 ]) 530 .borderRadius(10) 531 .monitorInvisibleArea(true) 532 .clip(true) 533 .duration(4000) 534 .state(this.state) 535 .reverse(this.reverse) 536 .fillMode(FillMode.Forwards) 537 .iterations(this.iterations) 538 .width(340) 539 .height(240) 540 .margin({ top: 100 }) 541 .onStart(() => { 542 this.preCallBack = "Start"; 543 console.info('ImageAnimator Start'); 544 }) 545 .onPause(() => { 546 this.preCallBack = "Pause"; 547 console.info('ImageAnimator Pause'); 548 }) 549 .onRepeat(() => { 550 console.info('ImageAnimator Repeat'); 551 }) 552 .onCancel(() => { 553 console.info('ImageAnimator Cancel'); 554 }) 555 .onFinish(() => { 556 console.info('ImageAnimator Finish'); 557 }) 558 ForEach(this.arr, (item: number) => { 559 Text(item.toString()) 560 .width('90%') 561 .height(150) 562 .backgroundColor(0xFFFFFF) 563 .borderRadius(15) 564 .fontSize(16) 565 .textAlign(TextAlign.Center) 566 .margin({ top: 10 }) 567 }, (item: string) => item) 568 }.width('100%') 569 } 570 .scrollable(ScrollDirection.Vertical) // 滚动方向纵向 571 .scrollBar(BarState.On) // 滚动条常驻显示 572 .scrollBarColor(Color.Gray) // 滚动条颜色 573 .scrollBarWidth(10) // 滚动条宽度 574 .friction(0.6) 575 .edgeEffect(EdgeEffect.None) 576 .onWillScroll((xOffset: number, yOffset: number, scrollState: ScrollState) => { 577 console.info(xOffset + ' ' + yOffset); 578 }) 579 .onScrollEdge((side: Edge) => { 580 console.info('To the edge'); 581 }) 582 .onScrollStop(() => { 583 console.info('Scroll Stop'); 584 }) 585 586 Text("上次触发的回调(Pause/Start):" + this.preCallBack) 587 .margin({ top: 60, left: 20 }) 588 }.width('100%').height('100%').backgroundColor(0xDCDCDC) 589 } 590} 591``` 592 593 594