1# @ohos.multimedia.movingphotoview (动态照片) 2 3用于播放动态照片文件并控制其播放状态的组件。 4 5> **说明:** 6> 7> 该组件从API Version 12开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 8> 当前不支持在预览器中使用MovingPhotoView组件。 9 10## 导入模块 11 12``` 13import { MovingPhotoView, MovingPhotoViewController, MovingPhotoViewAttribute } from '@kit.MediaLibraryKit'; 14``` 15 16## MovingPhotoView 17 18> **说明:** 19> 20> - 当前不支持动态属性设置。 21> - 当前不支持ArkUI通用属性ComponentOptions中expandSafeArea属性设置。 22> - 该组件长按触发播放时组件区域放大为1.1倍。 23> - 该组件使用[AVPlayer](../apis-media-kit/_a_v_player.md#avplayer)进行播放,同时开启的[AVPlayer](../apis-media-kit/_a_v_player.md#avplayer)个数不建议超过3个,超过3个可能会出现视频播放卡顿现象。 24 25MovingPhotoView(options: MovingPhotoViewOptions) 26 27**参数:** 28 29 30| 参数名 | 参数类型 | 必填 | 参数描述 | 31| ------- | --------------------------------------------------------- | ---- | -------------- | 32| options | [MovingPhotoViewOptions](#movingphotoviewoptions) | 是 | 动态照片信息。 | 33 34## MovingPhotoViewOptions 35 36 37| 参数名 | 参数类型 | 必填 | 参数描述 | 38| ----------- | ------------------------------------------------------------------------------------------------ | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------- | 39| movingPhoto | [MovingPhoto](js-apis-photoAccessHelper.md#movingphoto12) | 是 | 支持媒体库MovingPhoto数据源,具体信息详见[MovingPhoto说明](js-apis-photoAccessHelper.md#movingphoto12)。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | 40| controller | [MovingPhotoViewController](#movingphotoviewcontroller) | 否 | 设置动态照片控制器,可以控制动态照片的播放状态。<br/>**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 | 41 42## 属性 43 44除支持[通用属性](../apis-arkui/arkui-ts/ts-universal-attributes-size.md)外,还支持以下属性: 45 46### muted 47 48muted(isMuted: boolean) 49 50设置是否静音。 51 52**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 53 54**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 55 56**参数:** 57 58 59| 参数名 | 类型 | 必填 | 说明 | 60| ------- | ------- | ---- | ---------------------------- | 61| isMuted | boolean | 是 | 是否静音。<br/>默认值:false<br/>false:非静音<br/>true:静音| 62 63### objectFit 64 65objectFit(value: ImageFit) 66 67设置动态照片显示模式。 68 69**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 70 71**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 72 73**参数:** 74 75 76| 参数名 | 类型 | 必填 | 说明 | 77| ------ | ----------------------------------------------------------------------------- | ---- | -------------------------------- | 78| value | [ImageFit](../apis-arkui/arkui-ts/ts-appendix-enums.md#imagefit) | 是 | 视频显示模式。<br/>默认值:Cover | 79 80### autoPlayPeriod<sup>13+</sup> 81 82autoPlayPeriod(startTime: number, endTime: number) 83 84设置自动播放区间,附属于autoPlay的子配置项。 85 86在调用此方法前,需将[autoPlay](#autoplay13)设置为true,设置自动播放,否则指定的视频区间(startTime, endTime)无法生效。 87 88**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。 89 90**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 91 92**参数:** 93 94 95| 参数名 | 类型 | 必填 | 说明 | 96| ------- | ------- | ---- | ---------------------------- | 97| startTime| number| 是 | 区间播放开始时间,单位:ms。<br/>取值范围:[0,3000]| 98| endTime| number| 是 | 区间播放结束时间,单位:ms。<br/>取值范围:[0,3000]| 99 100### autoPlay<sup>13+</sup> 101 102autoPlay(isAutoPlay: boolean) 103 104设置自动播放,自动播放一遍视频,完成播放后显示静态图。 105 106**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。 107 108**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 109 110**参数:** 111 112 113| 参数名 | 类型 | 必填 | 说明 | 114| ------- | ------- | ---- | ---------------------------- | 115| isAutoPlay| boolean| 是 | 是否自动播放。<br/>false:不自动播放<br/>true:自动播放<br/>默认值:false| 116 117### repeatPlay<sup>13+</sup> 118 119repeatPlay(isRepeatPlay: boolean) 120 121设置循环播放,重复播放视频。 repeatPlay与autoPlay及长按播放互斥,repeatPlay设置时,autoPlay和长按播放均不生效。 122 123**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。 124 125**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 126 127**参数:** 128 129 130| 参数名 | 类型 | 必填 | 说明 | 131| ------- | ------- | ---- | ---------------------------- | 132| isRepeatPlay| boolean| 是 | 是否循环播放。<br/>false:不循环播放<br/>true:循环播放<br/>默认值:false| 133 134## 事件 135 136除支持[通用事件](../apis-arkui/arkui-ts/ts-universal-events-click.md)外,还支持以下事件: 137 138### onComplete<sup>13+</sup> 139 140onComplete(callback: MovingPhotoViewEventCallback) 141 142动态照片加载完成图片时触发该事件。 143 144**原子化服务API:** 从API version 13开始,该接口支持在原子化服务中使用。 145 146**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 147 148**参数:** 149 150 151| 参数名 | 类型 | 必填 | 说明 | 152| -------- | ------------------------------------------------------------- | ---- | ------------------------------ | 153| callback | [MovingPhotoViewEventCallback](#movingphotovieweventcallback) | 是 | 动态照片加载完成图片的回调。 | 154 155### onStart 156 157onStart(callback: MovingPhotoViewEventCallback) 158 159播放时触发该事件。 160 161**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 162 163**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 164 165**参数:** 166 167 168| 参数名 | 类型 | 必填 | 说明 | 169| -------- | ------------------------------------------------------------- | ---- | ------------------------------ | 170| callback | [MovingPhotoViewEventCallback](#movingphotovieweventcallback) | 是 | 动态照片开始播放时触发的回调。 | 171 172### onPause 173 174onPause(callback: MovingPhotoViewEventCallback) 175 176播放暂停时触发该事件。 177 178**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 179 180**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 181 182**参数:** 183 184 185| 参数名 | 类型 | 必填 | 说明 | 186| -------- | ------------------------------------------------------------- | ---- | ------------------------------ | 187| callback | [MovingPhotoViewEventCallback](#movingphotovieweventcallback) | 是 | 动态照片播放暂停时触发的回调。 | 188 189### onFinish 190 191onFinish(callback: MovingPhotoViewEventCallback) 192 193播放结束时触发该事件。 194 195**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 196 197**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 198 199**参数:** 200 201 202| 参数名 | 类型 | 必填 | 说明 | 203| -------- | ------------------------------------------------------------- | ---- | ------------------------------ | 204| callback | [MovingPhotoViewEventCallback](#movingphotovieweventcallback) | 是 | 动态照片播放结束时触发的回调。 | 205 206### onError 207 208onError(callback: MovingPhotoViewEventCallback) 209 210播放失败时触发该事件。 211 212**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 213 214**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 215 216**参数:** 217 218 219| 参数名 | 类型 | 必填 | 说明 | 220| -------- | ------------------------------------------------------------- | ---- | ------------------------------ | 221| callback | [MovingPhotoViewEventCallback](#movingphotovieweventcallback) | 是 | 动态照片播放失败时触发的回调。 | 222 223### onStop 224 225onStop(callback: MovingPhotoViewEventCallback) 226 227播放停止时触发该事件(当stop()方法被调用后触发)。 228 229**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 230 231**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 232 233**参数:** 234 235 236| 参数名 | 类型 | 必填 | 说明 | 237| -------- | ------------------------------------------------------------- | ---- | ------------------------------ | 238| callback | [MovingPhotoViewEventCallback](#movingphotovieweventcallback) | 是 | 动态照片停止播放时触发的回调。 | 239 240## MovingPhotoViewEventCallback 241 242declare type MovingPhotoViewEventCallback = () => void 243 244动态照片播放状态发生变化时触发的回调。 245 246## MovingPhotoViewController 247 248一个MovingPhotoViewController对象可以控制一个MovingPhotoView,可用视频播放实例请参考[@ohos.multimedia.media](../apis-media-kit/js-apis-media.md)。 249 250### startPlayback 251 252startPlayback(): void 253 254开始播放。 255 256**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 257 258**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 259 260### stopPlayback 261 262stopPlayback(): void 263 264停止播放,再次播放时从头开始播放。 265 266**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 267 268**系统能力:** SystemCapability.FileManagement.PhotoAccessHelper.Core 269 270## 示例1:多种形式播放动态照片 271 272```ts 273// xxx.ets 274import { photoAccessHelper } from '@kit.MediaLibraryKit'; 275import { emitter } from '@kit.BasicServicesKit'; 276import { dataSharePredicates } from '@kit.ArkData'; 277import { MovingPhotoView, MovingPhotoViewController, MovingPhotoViewAttribute } from '@kit.MediaLibraryKit'; 278 279const PHOTO_SELECT_EVENT_ID: number = 80001 280 281@Entry 282@Component 283struct MovingPhotoViewDemo { 284 @State src: photoAccessHelper.MovingPhoto | undefined = undefined 285 @State isMuted: boolean = false 286 controller: MovingPhotoViewController = new MovingPhotoViewController() 287 288 aboutToAppear(): void { 289 emitter.on({ 290 eventId: PHOTO_SELECT_EVENT_ID, 291 priority: emitter.EventPriority.IMMEDIATE, 292 }, (eventData: emitter.EventData) => { 293 this.src = AppStorage.get<photoAccessHelper.MovingPhoto>('mv_data') as photoAccessHelper.MovingPhoto 294 }) 295 } 296 297 aboutToDisappear(): void { 298 emitter.off(PHOTO_SELECT_EVENT_ID) 299 } 300 301 build() { 302 Column() { 303 Row() { 304 Button('PICK') 305 .margin(5) 306 .onClick(async () => { 307 let context = getContext(this) 308 try { 309 let uris: Array<string> = [] 310 const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions() 311 photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE 312 photoSelectOptions.maxSelectNumber = 2 313 const photoViewPicker = new photoAccessHelper.PhotoViewPicker() 314 let photoSelectResult: photoAccessHelper.PhotoSelectResult = await photoViewPicker.select(photoSelectOptions) 315 uris = photoSelectResult.photoUris 316 if (uris[0]) { 317 this.handlePickerResult(context, uris[0], new MediaDataHandlerMovingPhoto()) 318 } 319 } catch (e) { 320 console.error(`pick file failed`) 321 } 322 }) 323 } 324 .alignItems(VerticalAlign.Center) 325 .justifyContent(FlexAlign.Center) 326 .height('15%') 327 328 Row() { 329 Column() { 330 MovingPhotoView({ 331 movingPhoto: this.src, 332 controller: this.controller 333 }) 334 .width('100%') 335 .height('100%') 336 .muted(this.isMuted) 337 .autoPlay(true) 338 .repeatPlay(false) 339 .autoPlayPeriod(0, 600) 340 .objectFit(ImageFit.Cover) 341 .onComplete(() => { 342 console.log('Completed'); 343 }) 344 .onStart(() => { 345 console.log('onStart') 346 }) 347 .onFinish(() => { 348 console.log('onFinish') 349 }) 350 .onStop(() => { 351 console.log('onStop') 352 }) 353 .onError(() => { 354 console.log('onError') 355 }) 356 } 357 } 358 .height('70%') 359 360 Row() { 361 Button('start') 362 .onClick(() => { 363 this.controller.startPlayback() 364 }) 365 .margin(5) 366 Button('stop') 367 .onClick(() => { 368 this.controller.stopPlayback() 369 }) 370 .margin(5) 371 Button('mute') 372 .onClick(() => { 373 this.isMuted = !this.isMuted 374 }) 375 .margin(5) 376 } 377 .alignItems(VerticalAlign.Center) 378 .justifyContent(FlexAlign.Center) 379 .height('15%') 380 } 381 } 382 383 async handlePickerResult(context: Context, uri: string, handler: photoAccessHelper.MediaAssetDataHandler<photoAccessHelper.MovingPhoto>): Promise<void> { 384 let uriPredicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates(); 385 uriPredicates.equalTo('uri', uri) 386 let fetchOptions: photoAccessHelper.FetchOptions = { 387 fetchColumns: [], 388 predicates: uriPredicates 389 }; 390 let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context) 391 let assetResult = await phAccessHelper.getAssets(fetchOptions) 392 let asset = await assetResult.getFirstObject() 393 let requestOptions: photoAccessHelper.RequestOptions = { 394 deliveryMode: photoAccessHelper.DeliveryMode.FAST_MODE, 395 } 396 try { 397 photoAccessHelper.MediaAssetManager.requestMovingPhoto(context, asset, requestOptions, handler) 398 } catch (err) { 399 console.error("request error: ", err) 400 } 401 } 402} 403 404class MediaDataHandlerMovingPhoto implements photoAccessHelper.MediaAssetDataHandler<photoAccessHelper.MovingPhoto> { 405 async onDataPrepared(movingPhoto: photoAccessHelper.MovingPhoto) { 406 AppStorage.setOrCreate('mv_data', movingPhoto) 407 emitter.emit({ 408 eventId: PHOTO_SELECT_EVENT_ID, 409 priority: emitter.EventPriority.IMMEDIATE, 410 }, { 411 }) 412 } 413} 414``` 415 416## 示例2:在原子化服务中使用动态照片 417 418```ts 419// xxx.ets 420import { photoAccessHelper, MovingPhotoView, MovingPhotoViewController, MovingPhotoViewAttribute } from '@kit.MediaLibraryKit'; 421 422let context = getContext(this) 423let data: photoAccessHelper.MovingPhoto 424async function loading() { 425 try { 426 // 需要确保imageFileUri和videoFileUri对应的资源在应用沙箱存在 427 let imageFileUri = 'file://{bundleName}/data/storage/el2/base/haps/entry/files/xxx.jpg'; 428 let videoFileUri = 'file://{bundleName}/data/storage/el2/base/haps/entry/files/xxx.mp4'; 429 data = await photoAccessHelper.MediaAssetManager.loadMovingPhoto(context, imageFileUri, videoFileUri); 430 console.info('load moving photo successfully'); 431 } catch (err) { 432 console.error(`load moving photo failed with error: ${err.code}, ${err.message}`); 433 } 434} 435@Entry 436@Component 437struct Index { 438 controller: MovingPhotoViewController = new MovingPhotoViewController() 439 @State ImageFit: ImageFit | undefined | null = ImageFit.Contain; 440 @State flag: boolean = true; 441 @State autoPlayFlag: boolean = true; 442 @State repeatPlayFlag: boolean = false; 443 @State autoPlayPeriodStart: number = 0; 444 @State autoPlayPeriodEnd: number = 500; 445 aboutToAppear(): void { 446 loading() 447 } 448 449 build() { 450 NavDestination() { 451 Column() { 452 Stack({ alignContent: Alignment.BottomStart }) { 453 MovingPhotoView({ 454 movingPhoto: data, 455 controller: this.controller 456 }) 457 .width(300) 458 .height(400) 459 .muted(this.flag) 460 .objectFit(this.ImageFit) 461 .autoPlay(this.autoPlayFlag) 462 .autoPlayPeriod(this.autoPlayPeriodStart, this.autoPlayPeriodEnd) 463 .repeatPlay(this.repeatPlayFlag) 464 .onComplete(() => { 465 console.info('onComplete') 466 }) 467 .onStart(() => { 468 console.info('onStart') 469 }) 470 .onStop(() => { 471 console.info('onStop') 472 }) 473 .onPause(() => { 474 console.info('onPause') 475 }) 476 .onFinish(() => { 477 console.info('onFinish') 478 }) 479 .onError(() => { 480 console.info('onError') 481 }) 482 } 483 484 Row() { 485 Button('Play') 486 .onClick(() => { 487 this.controller.startPlayback() 488 }) 489 Button('StopPlay') 490 .onClick(() => { 491 this.controller.stopPlayback() 492 }) 493 Button('mute').id('MovingPhotoView_true') 494 .onClick(() => { 495 this.flag = false 496 }) 497 } 498 } 499 } 500 } 501} 502```