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