1# 转场动画的使用(ArkTs) 2 3## 场景介绍 4日常在应用时,经常需要衔接两个场景,或者两个镜头画面之间进行切换,切换时需要呈现一种平滑过渡效果。 5 6本例将为大家介绍下如何通过转场动画实现上述过渡效果。 7 8## 效果呈现 9本例最终效果如下: 10 11| 场景 | 效果图 | 12| ---------------------------------- | ----------------------------------------------------- | 13| 页面间转场--底部滑入转场 |  | 14| 页面间转场--自定义1:缩放动画转场 |  | 15| 页面间转场---自定义2:旋转动画转场 |  | 16| 组件内转场 |  | 17| 共享元素转场 |  | 18 19 20 21## 运行环境 22本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发: 23- IDE: DevEco Studio 4.0 Beta1 24- SDK: Ohos_sdk_public 4.0.7.5 (API Version 10 Beta1) 25## 实现思路 26* 构建应用首页,主要由5个相同样式的功能菜单组成,通过添加路由实现主页面与对应功能页面的链接跳转。 27 28* 功能页面的实现 29 30 * 页面间转场 31 32 * 底部滑入转场 33 34 通过给pageTransition()方法定义入场效果PageTransitionEnter以及出场效果PageTransitionExit,同时通过设置slide属性为SlideEffect.Bottom来实现从底部滑入动效。 35 36 * 缩放动画转场 37 38 通过设置pageTransition方法,配置进行配置转场参数。 39 40 * 旋转动画转场 41 42 在FullCustomTransition.ets的Column组件中添加TransitionElement组件,并且定义pageTransition方法。给Clomn组件添加opacity、scale、rotate属性,定义变量animValue用来控制Clomn组件的动效,在PageTransitionEnter和PageTransitionExit组件中动态改变myProgress的值,从而控制动画效果。 43 44 * 组件间转场 45 46 * 通过Image、Column、Text、Button等组件构建ComponentTransition.ets页面。 47 48 * 新建一个Image组件,并且添加两个transition属性,分别用于定义组件的插入动效和移除动效,从而实现组件间的转场。 49 50 * 设置变量isShow,用来控制上述步骤中Image组件的添加和移除,同时向Button组件的onClick添加animateTo方法,来使ComponentItem子组件动效生效。 51 * isShow默认状态为false,删除隐藏Image组件,同时删除动效生效。 52 53 * 当isShow状态更新为true时,插入Image组件,同时插入动效生效。 54 55 * 共享转场 56 57 通过给两个页面“SharedItem”和“SharePage” 的Image组件设置sharedTransition属性来实现,两个页面的组件配置为同一个id,则转场过程中会执行共享元素转场效果。 58 59## 开发步骤 601. 创建主界面。 61 62 添加媒体资源至resources > base > media目录下。 63 64  65 66 首页Index.ets引入首页列表常量数据:INDEX_ANIMATION_MODE(imgRes:设置按钮的背景图片,url:设置页面路由的地址),通过ForEach方法循环渲染列表常量数据。 67 具体代码如下: 68 69 ```ts 70 // entry/src/main/ets/pages/Index.ets 71 72 // 引入列表常量数据INDEX_ANIMATION_MODE 73 export const INDEX_ANIMATION_MODE = [ 74 { imgRes: $r('app.media.bg_bottom_anim_transition'), url: 'pages/BottomTransition' }, 75 { imgRes: $r('app.media.bg_custom1_anim_transition'), url: 'pages/CustomTransition' }, 76 { imgRes: $r('app.media.bg_custom2_anim_transition'), url: 'pages/FullCustomTransition' }, 77 { imgRes: $r('app.media.bg_element_anim_transition'), url: 'pages/ComponentTransition' }, 78 { imgRes: $r('app.media.bg_share_anim_transition'), url: 'pages/ShareItem' } 79 ]; 80 81 ... 82 Column() { 83 // ForEach循环渲染 84 ForEach(INDEX_ANIMATION_MODE, ({ imgRes , url }) => { 85 Row() 86 .backgroundImage(imgRes) 87 .backgroundImageSize(ImageSize.Cover) 88 .backgroundColor('#00000000') 89 .height(130) 90 .margin({ bottom: 30 }) 91 .width('100%') 92 .borderRadius(32) 93 .onClick(() => { 94 router.pushUrl({ url: url }) 95 }) 96 }, item => JSON.stringify(item)) 97 } 98 ``` 99 100 添加其它组件,以及样式,完成UI构建。 101 102 具体代码如下: 103 ```ts 104 // entry/src/main/ets/pages/Index.ets 105 import router from '@ohos.router'; 106 import hilog from '@ohos.hilog'; 107 @Entry 108 @Component 109 struct Index { 110 build() { 111 Column() { 112 Text($r('app.string.main_page_title')) 113 .fontSize(30) 114 .fontWeight(FontWeight.Regular) 115 .width('100%') 116 .margin({ top: 13, bottom: 27,left: 24}) 117 118 Scroll() { 119 Column() { 120 ForEach(INDEX_ANIMATION_MODE, ({ imgRes , url }) => { 121 Row() 122 .backgroundImage(imgRes) 123 .backgroundImageSize(ImageSize.Cover) 124 .backgroundColor('#00000000') 125 .height(130) 126 .margin({ bottom: 30 }) 127 .width('100%') 128 .borderRadius(32) 129 .onClick(() => { 130 router.pushUrl({ url: url }) 131 .catch(err => { 132 hilog.error(0xff00, '[ReadingRecorder]', `%{public}s, %{public}s`, err); 133 }); 134 }) 135 }, item => JSON.stringify(item)) 136 } 137 } 138 .align(Alignment.Top) 139 .layoutWeight(1) 140 .scrollBar(BarState.Off) 141 } 142 .height('100%') 143 .backgroundColor('#F1F3F5') 144 .padding({left:12 , right:12}) 145 } 146 } 147 ``` 148 1492. 实现页面间转场。 150 * 效果1:底部滑入。 151 152 该效果的实现,主要是通过在BottomTransition.ets中设置全局pageTransition()方法,该方法中自定义入场效果PageTransitionEnter以及出场效果PageTransitionExit,同时通过设置slide属性为SlideEffect.Bottom来实现从底部滑入动效。 153 154 具体代码如下: 155 156 ```ts 157 // entry/src/main/ets/pages/BottomTransition.ets 158 159 @Entry 160 @Component 161 struct BottomTransition { 162 private imgRes: string | Resource = $r('app.media.bg_transition'); 163 private imgFit: ImageFit = ImageFit.Fill; 164 165 build() { 166 Column() { 167 Image(this.imgRes) 168 .objectFit(this.imgFit) 169 .width('100%') 170 .height('100%') 171 } 172 173 } 174 175 // 页面转场通过全局pageTransition方法进行配置转场参数 176 pageTransition() { 177 // PageTransitionEnter自定义入场效果:设置slide属性为SlideEffect.Bottom 表示入场时从屏幕下方滑入。 178 PageTransitionEnter({ duration: 600, curve: Curve.Smooth }).slide(SlideEffect.Bottom); 179 // PageTransitionExit自定义出场效果:设置slide属性为SlideEffect.Bottom 退场时从屏幕下方滑出。 180 PageTransitionExit({ duration: 600, curve: Curve.Smooth }).slide(SlideEffect.Bottom); 181 } 182 } 183 184 ``` 185 186 * 效果2:页面入场时淡入和放大,退场时从右下角滑出。 187 188 * 在CustomTransition.ets中设置全局pageTransition()方法。 189 * pageTransition方法中自定义入场效果PageTransitionEnter:透明度设置从0.2到1;x、y轴缩放从0变化到1。 190 * pageTransition方法中自定义出场效果PageTransitionExit: x、y轴的偏移量为500。 191 192 具体代码如下: 193 194 ```ts 195 // entry/src/main/ets/pages/CustomTransition.ets 196 197 @Entry 198 @Component 199 struct CustomTransition { 200 private imgRes: string | Resource = $r('app.media.bg_transition'); 201 private imgFit: ImageFit = ImageFit.Fill; 202 203 build() { 204 Column() { 205 Image(this.imgRes) 206 .objectFit(this.imgFit) 207 .width('100%') 208 .height('100%') 209 } 210 } 211 212 // 页面转场通过全局pageTransition方法进行配置转场参数 213 pageTransition() { 214 // 进场时透明度设置从0.2到1;x、y轴缩放从0变化到1 215 PageTransitionEnter({ duration: 600, curve: Curve.Smooth }).opacity(0.2).scale({ x: 0, y: 0 }) 216 // 退场时x、y轴的偏移量为500 217 PageTransitionExit({ duration: 600, curve: Curve.Smooth }).translate({ x: 500, y: 500 }) 218 } 219 } 220 ``` 221 222 * 效果3:页面入场时淡入和放大,同时顺时针旋转;退场时淡出和缩小,同时逆时针旋转。 223 224 * 在FullCustomTransition.ets中添加Column组件。 225 226 * 向Column组件添加属性:opacity、scale、rotate,来控制动效的淡入淡出、缩放以及旋转效果。 227 228 * 定义变量animValue用来,通过animValue值得变化来控制Column组件的动效。 229 * 在FullCustomTransition.ets中定义全局pageTransition()方法。 230 * pageTransition方法中自定义入场效果PageTransitionEnter。 231 232 animValue值实时变化,0 --> 1,从而渲染 入场时淡入、放大以及顺时针旋转效果。 233 * pageTransition方法中自定义出场效果PageTransitionExit。 234 235 animValue值实时变化,1 --> 0,从而渲染 出场时淡出、缩小以及逆时针旋转效果。 236 237 具体代码如下: 238 239 ```ts 240 // entry/src/main/ets/pages/FullCustomTransition.ets 241 242 @Entry 243 @Component 244 struct FullCustomTransition { 245 @State animValue: number = 1; 246 private imgRes: string | Resource = $r('app.media.bg_transition'); 247 private imgFit: ImageFit = ImageFit.Fill; 248 249 build() { 250 Column() { 251 Image(this.imgRes) 252 .objectFit(this.imgFit) 253 .width('100%') 254 .height('100%') 255 } 256 // 设置淡入、淡出效果 257 .opacity(this.animValue) 258 // 设置缩放 259 .scale({ x: this.animValue, y: this.animValue }) 260 // 设置旋转角度 261 .rotate({ 262 z: 1, 263 angle: 360 * this.animValue 264 }) 265 } 266 267 // 页面转场通过全局pageTransition方法进行配置转场参数 268 pageTransition() { 269 PageTransitionEnter({ duration: 600, curve: Curve.Smooth }) 270 // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0 - 1) 271 .onEnter((type: RouteType, progress: number) => { 272 // 入场动效过程中,实时更新this.animValue的值 273 this.animValue = progress 274 }); 275 PageTransitionExit({ duration: 600, curve: Curve.Smooth }) 276 // 出场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0 - 1) 277 .onExit((type: RouteType, progress: number) => { 278 // 入场动效过程中,实时更新this.animValue的值 279 this.animValue = 1 - progress 280 }); 281 } 282 } 283 ``` 284 285 2863. 实现组件内转场。 287 288 * 通过Image、Column、Text、Button等组件构建ComponentTransition.ets页面。 289 290 具体代码如下: 291 292 ```ts 293 // entry/src/main/ets/pages/ComponentTransition.ets 294 295 @Entry 296 @Component 297 struct ComponentTransition { 298 299 build() { 300 Column() { 301 Row() { 302 Image($r('app.media.ic_public_back')) 303 .width(20) 304 .height(20) 305 .responseRegion({width:'100%',height: '100%'}) 306 .onClick(() => { 307 this.getUIContext().getRouter().back(); 308 }) 309 310 Text($r('app.string.Component_transition_header')) 311 .fontColor(Color.Black) 312 .fontWeight(FontWeight.Regular) 313 .fontSize(25) 314 .margin({left:18,right:18}) 315 } 316 .height(30) 317 .width('100%') 318 .margin({ top: 20, bottom: 27,left: 24}) 319 320 321 Image($r('app.media.bg_element')) 322 .objectFit(ImageFit.Fill) 323 .borderRadius(20) 324 .margin({ bottom: 20 }) 325 .width('100%') 326 .height(300) 327 328 Button($r('app.string.Component_transition_toggle')) 329 .height(40) 330 .width(120) 331 .fontColor(Color.White) 332 .backgroundColor($r('app.color.light_blue')) 333 } 334 .padding({left:20,right:20}) 335 .height('100%') 336 .width('100%') 337 } 338 } 339 340 ``` 341 342 * 新建一个Image组件,并且添加两个transition属性,分别用于定义组件的插入动效和移除动效,来实现组件转场间。 343 344 具体代码如下: 345 346 ```ts 347 // entry/src/main/ets/pages/ComponentTransition.ets 348 ... 349 Image($r('app.media.bg_share')) 350 .objectFit(ImageFit.Fill) 351 .borderRadius(20) 352 .margin({ bottom: 20 }) 353 .height(300) 354 .width('100%') 355 // 插入动效 356 .transition({ 357 type: TransitionType.Insert, 358 scale: { x: 0.5, y: 0.5 }, 359 opacity: 0 360 }) 361 // 删除隐藏动效 362 .transition({ 363 type: TransitionType.Delete, 364 rotate: { x: 0, y: 1, z: 0, angle: 360 }, 365 opacity: 0 366 }) 367 ``` 368 369 370 - 设置变量isShow,用来控制上述步骤中Image组件的添加和移除,同时向Button组件的onClick添加animateTo方法,来使ComponentItem子组件动效生效。 371 372 * isShow默认状态为false,删除隐藏Image组件,同时删除动效生效。 373 374 * 当isShow状态更新为true时,插入Image组件,同时插入动效生效。 375 376 具体代码如下: 377 378 ```ts 379 // entry/src/main/ets/pages/ComponentTransition.ets 380 381 ... 382 @State isShow: boolean = false; 383 ... 384 // isShow为True,插入Image组件,同时插入动效生效;isShow为False,删除隐藏Image组件,同时删除动效生效 385 if (this.isShow) { 386 Image($r('app.media.bg_share')) 387 .objectFit(ImageFit.Fill) 388 .borderRadius(20) 389 .margin({ bottom: 20 }) 390 .height(300) 391 .width('100%') 392 // 插入动效 393 .transition({ 394 type: TransitionType.Insert, 395 scale: { x: 0.5, y: 0.5 }, 396 opacity: 0 397 }) 398 // 删除隐藏动效 399 .transition({ 400 type: TransitionType.Delete, 401 rotate: { x: 0, y: 1, z: 0, angle: 360 }, 402 opacity: 0 403 }) 404 } 405 ... 406 Button($r('app.string.Component_transition_toggle')) 407 ... 408 .onClick(() => { 409 animateTo({ duration: 600 }, () => { 410 this.isShow = !this.isShow; 411 }) 412 }) 413 ``` 414 415 ComponentTransition.ets的完整代码如下: 416 417 ```ts 418 // entry/src/main/ets/pages/ComponentTransition.ets 419 @Entry 420 @Component 421 struct ComponentTransition { 422 @State isShow: boolean = false; 423 424 build() { 425 Column() { 426 // 页面title区域,含返回功能以及title显示 427 Row() { 428 Image($r('app.media.ic_public_back')) 429 .width(20) 430 .height(20) 431 .responseRegion({ 432 width:'100%', 433 height: '100%' 434 }) 435 .onClick(() => { 436 this.getUIContext().getRouter().back(); 437 }) 438 439 Text($r('app.string.Component_transition_header')) 440 .fontColor(Color.Black) 441 .fontWeight(FontWeight.Regular) 442 .fontSize(25) 443 .height(300) 444 .margin({ left:18, right:18 }) 445 } 446 .height(30) 447 .width('100%') 448 .margin({ top: 20, bottom: 27,left: 24}) 449 450 // 页面内容区域 451 // isShow为True,插入Image组件,同时插入动效生效;isShow为False,删除隐藏Image组件,同时删除动效生效 452 if (this.isShow) { 453 Image($r('app.media.bg_share')) 454 .objectFit(ImageFit.Fill) 455 .borderRadius(20) 456 .margin({ bottom: 20 }) 457 .height(300) 458 .width('100%') 459 // 插入动效 460 .transition({ 461 type: TransitionType.Insert, 462 scale: { x: 0.5, y: 0.5 }, 463 opacity: 0 464 }) 465 // 删除隐藏动效 466 .transition({ 467 type: TransitionType.Delete, 468 rotate: { x: 0, y: 1, z: 0, angle: 360 }, 469 opacity: 0 470 }) 471 } 472 473 Image($r('app.media.bg_element')) 474 .objectFit(ImageFit.Fill) 475 .borderRadius(20) 476 .margin({ bottom: 20 }) 477 .width('100%') 478 .height(300) 479 Button($r('app.string.Component_transition_toggle')) 480 .height(40) 481 .width(120) 482 .fontColor(Color.White) 483 .backgroundColor($r('app.color.light_blue')) 484 .onClick(() => { 485 animateTo({ duration: 600 }, () => { 486 console.log('console-- ' +this.isShow) 487 this.isShow = !this.isShow; 488 }) 489 }) 490 } 491 .padding({ 492 left:(20), 493 right:(20) 494 }) 495 .height('100%') 496 .width('100%') 497 } 498 } 499 ``` 500 501 5024. 实现元素共享转场。 503 504 共享元素转场通过给组件设置sharedTransition属性来实现,两个页面的组件配置为同一个id,则转场过程中会执行共享元素转场效果。 505 506 * 通过Image、Column、Text等组件构建ShareItem.ets页面,给内容区域的Image组件设置sharedTransition属性标记该元素为共享元素,组件转场id设置为“shareID”, 同时设置共享元素转场效果。 507 508 具体代码如下: 509 510 ```ts 511 // entry/src/main/ets/pages/ShareItem.ets 512 513 import hilog from '@ohos.hilog'; 514 515 @Entry 516 @Component 517 struct ShareItem { 518 // 自定义页面内容区域 519 @Builder PreviewArea() { 520 Column() { 521 Image($r('app.media.bg_transition')) 522 .width('100%') 523 .height(300) 524 .borderRadius(24) 525 .margin({ bottom: 12 }) 526 // 设置sharedTransition属性标记该元素为共享元素,转场id为“shareId” 527 .sharedTransition('shareId', { 528 duration: 600, 529 curve: Curve.Smooth, 530 delay: 100 531 }) 532 533 .onClick(() => { 534 // 路由切换 535 router.pushUrl({ url: 'pages/SharePage' }) 536 .catch(err => { 537 hilog.error(0xFF00, '[ReadingRecorder]', `%{public}s, %{public}s`, err); 538 }); 539 }) 540 Text($r('app.string.Share_Item_hint')) 541 .width('100%') 542 .textAlign(TextAlign.Center) 543 .fontSize(20) 544 .fontWeight(FontWeight.Regular) 545 .fontColor($r('app.color.share_item_content_font')) 546 } 547 .borderRadius(24) 548 .backgroundColor(Color.White) 549 .width('100%') 550 .padding({ top: 13, left: 12, right: 12,bottom:12}) 551 } 552 553 build() { 554 Column() { 555 // 页面title区域,含返回功能以及title显示 556 Row() { 557 Image($r('app.media.ic_public_back')) 558 .width(20) 559 .height(20) 560 .responseRegion({ 561 width:'100%', 562 height: '100%' 563 }) 564 .onClick(() => { 565 this.getUIContext().getRouter().back(); 566 }) 567 568 Text($r('app.string.Share_Item_header')) 569 .fontColor(Color.Black) 570 .fontWeight(FontWeight.Regular) 571 .fontSize(25) 572 .margin({ left:18, right:18 }) 573 } 574 .height(30) 575 .width('100%') 576 .margin({ top: 20, bottom: 27,left: 24}) 577 this.PreviewArea() 578 } 579 .width('100%') 580 .height('100%') 581 .backgroundColor($r('app.color.grey_light')) 582 .padding({left:12,right:12}) 583 } 584 } 585 ``` 586 587 * pages/SharePage.ets页面中,给Image组件设置sharedTransition属性,同时组件转场id设置为“shareID”,从而可以共享上述步骤的转场动效。 588 589 具体代码如下: 590 ```ts 591 // entry/src/main/ets/pages/SharePage.ets 592 @Entry 593 @Component 594 struct SharePage { 595 build() { 596 Column() { 597 Image($r('app.media.bg_transition')) 598 .objectFit(ImageFit.Fill) 599 .width('100%') 600 .height('100%') 601 .sharedTransition('shareId', { 602 duration: 600, 603 curve: Curve.Smooth, 604 delay: 100 605 }) 606 } 607 } 608 } 609 ``` 610 611 612## 完整代码 613本例完整代码如下: 614 615应用首页: /entry/src/main/ets/pages/Index.ets。 616 617```ts 618// entry/src/main/ets/pages/Index.ets 619import router from '@ohos.router'; 620import hilog from '@ohos.hilog'; 621 622@Entry 623@Component 624struct Index { 625 build() { 626 Column() { 627 Text($r('app.string.main_page_title')) 628 .fontSize(30) 629 .fontWeight(FontWeight.Regular) 630 .width('100%') 631 .margin({ top: 13, bottom: 27,left: 24}) 632 633 Scroll() { 634 Column() { 635 ForEach(INDEX_ANIMATION_MODE, ({ imgRes , url }) => { 636 Row() 637 .backgroundImage(imgRes) 638 .backgroundImageSize(ImageSize.Cover) 639 .backgroundColor('#00000000') 640 .height(130) 641 .margin({ bottom: 30 }) 642 .width('100%') 643 .borderRadius(32) 644 .onClick(() => { 645 router.pushUrl({ url: url }) 646 .catch(err => { 647 hilog.error(0xff00, '[ReadingRecorder]', `%{public}s, %{public}s`, err); 648 }); 649 }) 650 }, item => JSON.stringify(item)) 651 } 652 } 653 .align(Alignment.Top) 654 .layoutWeight(1) 655 .scrollBar(BarState.Off) 656 } 657 .height('100%') 658 .backgroundColor('#F1F3F5') 659 .padding({left:12 , right:12}) 660 } 661} 662``` 663 664底部滑出页面:/entry/src/main/ets/pages/BottomTransition.ets。 665 666```ts 667// entry/src/main/ets/pages/BottomTransition.ets 668 669@Entry 670@Component 671struct BottomTransition { 672 private imgRes: string | Resource = $r('app.media.bg_transition'); 673 private imgFit: ImageFit = ImageFit.Fill; 674 675 build() { 676 Column() { 677 Image(this.imgRes) 678 .objectFit(this.imgFit) 679 .width('100%') 680 .height('100%') 681 } 682 683 } 684 685 // 页面转场通过全局pageTransition方法进行配置转场参数 686 pageTransition() { 687 // PageTransitionEnter自定义入场效果:设置slide属性为SlideEffect.Bottom 表示入场时从屏幕下方滑入。 688 PageTransitionEnter({ duration: 600, curve: Curve.Smooth }).slide(SlideEffect.Bottom); 689 // PageTransitionExit自定义出场效果:设置slide属性为SlideEffect.Bottom 退场时从屏幕下方滑出。 690 PageTransitionExit({ duration: 600, curve: Curve.Smooth }).slide(SlideEffect.Bottom); 691 } 692} 693``` 694 695自定义1 缩放动画转场页面:/entry/src/main/ets/pages/CustomTransition.ets。 696 697```ts 698// entry/src/main/ets/pages/CustomTransition.ets 699@Entry 700@Component 701struct CustomTransition { 702 private imgRes: string | Resource = $r('app.media.bg_transition'); 703 private imgFit: ImageFit = ImageFit.Fill; 704 build() { 705 Column() { 706 Image(this.imgRes) 707 .objectFit(this.imgFit) 708 .width('100%') 709 .height('100%') 710 } 711 } 712 // 页面转场通过全局pageTransition方法进行配置转场参数 713 pageTransition() { 714 // 进场时透明度设置从0.2到1;x、y轴缩放从0变化到1 715 PageTransitionEnter({ duration: 600, curve: Curve.Smooth }).opacity(0.2).scale({ x: 0, y: 0 }) 716 // 退场时x、y轴的偏移量为500 717 PageTransitionExit({ duration: 600, curve: Curve.Smooth }).translate({ x: 500, y: 500 }) 718 } 719} 720``` 721 722自定义2 旋转动画转场: /entry/src/main/ets/pages/FullCustomTransition.ets。 723 724```ts 725@Entry 726@Component 727struct FullCustomTransition { 728 @State animValue: number = 1; 729 private imgRes: string | Resource = $r('app.media.bg_transition'); 730 private imgFit: ImageFit = ImageFit.Fill; 731 build() { 732 Column() { 733 Image(this.imgRes) 734 .objectFit(this.imgFit) 735 .width('100%') 736 .height('100%') 737 } 738 // 设置淡入、淡出效果 739 .opacity(this.animValue) 740 // 设置缩放 741 .scale({ x: this.animValue, y: this.animValue }) 742 // 设置旋转角度 743 .rotate({ 744 z: 1, 745 angle: 360 * this.animValue 746 }) 747 } 748 // 页面转场通过全局pageTransition方法进行配置转场参数 749 pageTransition() { 750 PageTransitionEnter({ duration: 600, curve: Curve.Smooth }) 751 // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0 - 1) 752 .onEnter((type: RouteType, progress: number) => { 753 // 入场动效过程中,实时更新this.animValue的值 754 this.animValue = progress 755 }); 756 PageTransitionExit({ duration: 600, curve: Curve.Smooth }) 757 // 出场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0 - 1) 758 .onExit((type: RouteType, progress: number) => { 759 // 入场动效过程中,实时更新this.animValue的值 760 this.animValue = 1 - progress 761 }); 762 } 763} 764``` 765 766组件内转场页面: /entry/src/main/ets/pages/ComponentTransition.ets。 767 768```ts 769 @Entry 770 @Component 771 struct ComponentTransition { 772 @State isShow: boolean = false; 773 build() { 774 Column() { 775 // 页面title区域,含返回功能以及title显示 776 Row() { 777 Image($r('app.media.ic_public_back')) 778 .width(20) 779 .height(20) 780 .responseRegion({ 781 width:'100%', 782 height: '100%' 783 }) 784 .onClick(() => { 785 this.getUIContext().getRouter().back(); 786 }) 787 Text($r('app.string.Component_transition_header')) 788 .fontColor(Color.Black) 789 .fontWeight(FontWeight.Regular) 790 .fontSize(25) 791 .margin({left:18, right:18}) 792 } 793 .height(30) 794 .width('100%') 795 .margin({ top: 20, bottom: 27,left: 24}) 796 797 // 页面内容区域 798 // isShow为True,插入Image组件,同时插入动效生效;isShow为False,删除隐藏Image组件,同时删除动效生效 799 if (this.isShow) { 800 Image($r('app.media.bg_share')) 801 .objectFit(ImageFit.Fill) 802 .borderRadius(20) 803 .margin({ bottom: 20 }) 804 .height(300) 805 .width('100%') 806 // 插入动效 807 .transition({ 808 type: TransitionType.Insert, 809 scale: { x: 0.5, y: 0.5 }, 810 opacity: 0 811 }) 812 // 删除隐藏动效 813 .transition({ 814 type: TransitionType.Delete, 815 rotate: { x: 0, y: 1, z: 0, angle: 360 }, 816 opacity: 0 817 }) 818 } 819 820 821 Image($r('app.media.bg_element')) 822 .objectFit(ImageFit.Fill) 823 .borderRadius(20) 824 .margin({ bottom: 20 }) 825 .width('100%') 826 .height(300) 827 828 Button($r('app.string.Component_transition_toggle')) 829 .height(40) 830 .width(120) 831 .fontColor(Color.White) 832 .backgroundColor($r('app.color.light_blue')) 833 .onClick(() => { 834 animateTo({ duration: 600 }, () => { 835 this.isShow = !this.isShow; 836 }) 837 }) 838 } 839 .padding({left:20,right:20}) 840 .height('100%') 841 .width('100%') 842 } 843 } 844``` 845 846 847共享元素转场部件:/entry/src/main/ets/pages/ShareItem.ets。 848 849```ts 850import hilog from '@ohos.hilog'; 851 852@Entry 853@Component 854struct ShareItem { 855 // 自定义页面内容区域 856 @Builder PreviewArea() { 857 Column() { 858 Image($r('app.media.bg_transition')) 859 .width('100%') 860 .height(300) 861 .borderRadius(24) 862 .margin({ bottom: 12 }) 863 // 设置sharedTransition属性标记该元素为共享元素,转场id为“shareId” 864 .sharedTransition('shareId', { 865 duration: 600, 866 curve: Curve.Smooth, 867 delay: 100 868 }) 869 870 .onClick(() => { 871 // 路由切换 872 router.pushUrl({ url: 'pages/SharePage' }) 873 .catch(err => { 874 hilog.error(0xFF00, '[ReadingRecorder]', `%{public}s, %{public}s`, err); 875 }); 876 }) 877 Text($r('app.string.Share_Item_hint')) 878 .width('100%') 879 .textAlign(TextAlign.Center) 880 .fontSize(20) 881 .fontWeight(FontWeight.Regular) 882 .fontColor($r('app.color.share_item_content_font')) 883 } 884 .borderRadius(24) 885 .backgroundColor(Color.White) 886 .width('100%') 887 .padding({ top: 13, left: 12, right: 12,bottom:12}) 888 } 889 890 build() { 891 Column() { 892 // 页面title区域,含返回功能以及title显示 893 Row() { 894 Image($r('app.media.ic_public_back')) 895 .width(20) 896 .height(20) 897 .responseRegion({ 898 width:'100%', 899 height: '100%' 900 }) 901 .onClick(() => { 902 this.getUIContext().getRouter().back(); 903 }) 904 905 Text($r('app.string.Share_Item_header')) 906 .fontColor(Color.Black) 907 .fontWeight(FontWeight.Regular) 908 .fontSize(25) 909 .margin({ left:18, right:18 }) 910 } 911 .height(30) 912 .width('100%') 913 .margin({ top: 20, bottom: 27,left: 24}) 914 this.PreviewArea() 915 } 916 .width('100%') 917 .height('100%') 918 .backgroundColor($r('app.color.grey_light')) 919 .padding({left:12,right:12}) 920 } 921} 922``` 923 924共享元素转场页面:/entry/src/main/ets/pages/SharePage.ets。 925 926```ts 927@Entry 928@Component 929struct SharePage { 930 build() { 931 Column() { 932 Image($r('app.media.bg_transition')) 933 .objectFit(ImageFit.Fill) 934 .width('100%') 935 .height('100%') 936 .sharedTransition('shareId', { 937 duration: 600, 938 curve: Curve.Smooth, 939 delay: 100 940 }) 941 } 942 } 943} 944``` 945 946 ## 参考 947 948- [图形变换](../application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-transformation.md) 949 950- [页面间转场](../application-dev/reference/apis-arkui/arkui-ts/ts-page-transition-animation.md) 951 952- [组件内转场](../application-dev/ui/arkts-shared-element-transition.md) 953 954- [共享元素转场](../application-dev/reference/apis-arkui/arkui-ts/ts-transition-animation-shared-elements.md) 955 956 957