1# 页面转场动画 2 3 4两个页面间发生跳转,一个页面消失,另一个页面出现,这时可以配置各自页面的页面转场参数实现自定义的页面转场效果。[页面转场](../reference/arkui-ts/ts-page-transition-animation.md)效果写在pageTransition函数中,通过PageTransitionEnter和PageTransitionExit指定页面进入和退出的动画效果。 5 6 7PageTransitionEnter的接口为: 8 9 10 11```ts 12PageTransitionEnter({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number}) 13``` 14 15 16PageTransitionExit的接口为: 17 18 19 20```ts 21PageTransitionExit({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number}) 22``` 23 24 25上述接口定义了PageTransitionEnter和PageTransitionExit组件,可通过slide、translate、scale、opacity属性定义不同的页面转场效果。对于PageTransitionEnter而言,这些效果表示入场时起点值,对于PageTransitionExit而言,这些效果表示退场的终点值,这一点与组件转场transition配置方法类似。此外,PageTransitionEnter提供了onEnter接口进行自定义页面入场动画的回调,PageTransitionExit提供了onExit接口进行自定义页面退场动画的回调。 26 27 28上述接口中的参数type,表示路由生效的类型,这一点开发者容易混淆其含义。页面转场的两个页面,必定有一个页面退出,一个页面进入。如果通过router.pushUrl操作从页面A跳转到页面B,则页面A退出,做页面退场动画,页面B进入,做页面入场动画。如果通过router.back操作从页面B返回到页面A,则页面B退出,做页面退场动画,页面A进入,做页面入场动画。即页面的PageTransitionEnter既可能是由于新增页面(push,入栈)引起的新页面的入场动画,也可能是由于页面返回(back,或pop,出栈)引起的页面栈中老页面的入场动画,为了能区分这两种形式的入场动画,提供了type参数,这样开发者能完全定义所有类型的页面转场效果。 29 30 31## type配置为RouteType.None 32 33type为RouteType.None表示对页面栈的push、pop操作均生效,type的默认值为RouteType.None。 34 35 36```ts 37// page A 38pageTransition() { 39 // 定义页面进入时的效果,从左侧滑入,时长为1200ms,无论页面栈发生push还是pop操作均可生效 40 PageTransitionEnter({ type: RouteType.None, duration: 1200 }) 41 .slide(SlideEffect.Left) 42 // 定义页面退出时的效果,向左侧滑出,时长为1000ms,无论页面栈发生push还是pop操作均可生效 43 PageTransitionExit({ type: RouteType.None, duration: 1000 }) 44 .slide(SlideEffect.Left) 45} 46``` 47 48 49 50```ts 51// page B 52pageTransition() { 53 // 定义页面进入时的效果,从右侧滑入,时长为1000ms,无论页面栈发生push还是pop操作均可生效 54 PageTransitionEnter({ type: RouteType.None, duration: 1000 }) 55 .slide(SlideEffect.Right) 56 // 定义页面退出时的效果,向右侧滑出,时长为1200ms,无论页面栈发生push还是pop操作均可生效 57 PageTransitionExit({ type: RouteType.None, duration: 1200 }) 58 .slide(SlideEffect.Right) 59} 60``` 61 62 63假设页面跳转配置为多实例模式,即页面栈中允许存在重复的页面。可能会有4种场景,对应的页面转场效果如下表。 64 65 66| 路由操作 | 页面A转场效果 | 页面B转场效果 | 67| ---------------------------- | ---------------------------------- | ---------------------------------- | 68| router.pushUrl,从页面A跳转到新增的页面B | 页面退出,PageTransitionExit生效,向左侧滑出屏幕 | 页面进入,PageTransitionEnter生效,从右侧滑入屏幕 | 69| router.back,从页面B返回到页面A | 页面进入,PageTransitionEnter生效,从左侧滑入屏幕 | 页面退出,PageTransitionExit生效,向右侧滑出屏幕 | 70| router.pushUrl,从页面B跳转到新增的页面A | 页面进入,PageTransitionEnter生效,从左侧滑入屏幕 | 页面退出,PageTransitionExit生效,向右侧滑出屏幕 | 71| router.back,从页面A返回到页面B | 页面退出,PageTransitionExit生效,向左侧滑出屏幕 | 页面进入,PageTransitionEnter生效,从右侧滑入屏幕 | 72 73 74如果希望pushUrl进入的页面总是从右侧滑入,back时退出的页面总是从右侧滑出,则上表中的第3、4种情况不满足要求,那么需要完整的定义4个页面转场效果。 75 76 77## type配置为RouteType.Push或RouteType.Pop 78 79type为RouteType.Push表示仅对页面栈的push操作生效,type为RouteType.Pop表示仅对页面栈的pop操作生效。 80 81 82```ts 83// page A 84pageTransition() { 85 // 定义页面进入时的效果,从右侧滑入,时长为1200ms,页面栈发生push操作时该效果才生效 86 PageTransitionEnter({ type: RouteType.Push, duration: 1200 }) 87 .slide(SlideEffect.Right) 88 // 定义页面进入时的效果,从左侧滑入,时长为1200ms,页面栈发生pop操作时该效果才生效 89 PageTransitionEnter({ type: RouteType.Pop, duration: 1200 }) 90 .slide(SlideEffect.Left) 91 // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效 92 PageTransitionExit({ type: RouteType.Push, duration: 1000 }) 93 .slide(SlideEffect.Left) 94 // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效 95 PageTransitionExit({ type: RouteType.Pop, duration: 1000 }) 96 .slide(SlideEffect.Right) 97} 98``` 99 100 101 102```ts 103// page B 104pageTransition() { 105 // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效 106 PageTransitionEnter({ type: RouteType.Push, duration: 1000 }) 107 .slide(SlideEffect.Right) 108 // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效 109 PageTransitionEnter({ type: RouteType.Pop, duration: 1000 }) 110 .slide(SlideEffect.Left) 111 // 定义页面退出时的效果,向左侧滑出,时长为1200ms,页面栈发生push操作时该效果才生效 112 PageTransitionExit({ type: RouteType.Push, duration: 1200 }) 113 .slide(SlideEffect.Left) 114 // 定义页面退出时的效果,向右侧滑出,时长为1200ms,页面栈发生pop操作时该效果才生效 115 PageTransitionExit({ type: RouteType.Pop, duration: 1200 }) 116 .slide(SlideEffect.Right) 117} 118``` 119 120 121以上代码则完整的定义了所有可能的页面转场样式。假设页面跳转配置为多实例模式,即页面栈中允许存在重复的页面。可能会有4种场景,对应的页面转场效果如下表。 122 123 124| 路由操作 | 页面A转场效果 | 页面B转场效果 | 125| ---------------------------- | ---------------------------------------- | ---------------------------------------- | 126| router.pushUrl,从页面A跳转到新增的页面B | 页面退出,PageTransitionExit且type为RouteType.Push的转场样式生效,向左侧滑出屏幕 | 页面进入,PageTransitionEnter且type为RouteType.Push的转场样式生效,从右侧滑入屏幕 | 127| router.back,从页面B返回到页面A | 页面进入,PageTransitionEnter且type为RouteType.Pop的转场样式生效,从左侧滑入屏幕 | 页面退出,PageTransitionExit且type为RouteType.Pop的转场样式生效,向右侧滑出屏幕 | 128| router.pushUrl,从页面B跳转到新增的页面A | 页面进入,PageTransitionEnter且type为RouteType.Push的转场样式生效,从右侧滑入屏幕 | 页面退出,PageTransitionExit且type为RouteType.Push的转场样式生效,向左侧滑出屏幕 | 129| router.back,从页面A返回到页面B | 页面退出,PageTransitionExit且type为RouteType.Pop的转场样式生效,向右侧滑出屏幕 | 页面进入,PageTransitionEnter且type为RouteType.Pop的转场样式生效,从左侧滑入屏幕 | 130 131 132>**说明:** 133> 134> 1. 由于每个页面的页面转场样式都可由开发者独立配置,而页面转场涉及到两个页面,开发者应考虑两个页面的页面转场效果的衔接,如时长尽量保持一致。 135> 136> 2. 如果没有定义匹配的页面转场样式,则该页面使用系统默认的页面转场样式。 137 138 139## 禁用某页面的页面转场 140 141 142```ts 143pageTransition() { 144 PageTransitionEnter({ type: RouteType.None, duration: 0 }) 145 PageTransitionExit({ type: RouteType.None, duration: 0 }) 146} 147``` 148 149 150通过设置页面转场的时长为0,可使该页面无页面转场动画。 151 152 153## 场景示例 154 155下面介绍定义了所有的四种页面转场样式的页面转场动画示例。 156 157 158 159```ts 160// page A 161import router from '@ohos.router'; 162@Entry 163@Component 164struct PageTransitionSrc1 { 165 build() { 166 Column() { 167 Image($r('app.media.mountain')) 168 .width('90%') 169 .height('80%') 170 .objectFit(ImageFit.Fill) 171 .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 172 .margin(30) 173 174 Row({ space: 10 }) { 175 Button("pushUrl") 176 .onClick(() => { 177 // 路由到下一个页面,push操作 178 router.pushUrl({ url: 'pages/myTest/pageTransitionDst1' }); 179 }) 180 Button("back") 181 .onClick(() => { 182 // 返回到上一页面,相当于pop操作 183 router.back(); 184 }) 185 }.justifyContent(FlexAlign.Center) 186 } 187 .width("100%").height("100%") 188 .alignItems(HorizontalAlign.Center) 189 } 190 191 pageTransition() { 192 // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效 193 PageTransitionEnter({ type: RouteType.Push, duration: 1000 }) 194 .slide(SlideEffect.Right) 195 // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效 196 PageTransitionEnter({ type: RouteType.Pop, duration: 1000 }) 197 .slide(SlideEffect.Left) 198 // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效 199 PageTransitionExit({ type: RouteType.Push, duration: 1000 }) 200 .slide(SlideEffect.Left) 201 // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效 202 PageTransitionExit({ type: RouteType.Pop, duration: 1000 }) 203 .slide(SlideEffect.Right) 204 } 205} 206``` 207 208 209 210 211```ts 212// page B 213import router from '@ohos.router'; 214@Entry 215@Component 216struct PageTransitionDst1 { 217 build() { 218 Column() { 219 Image($r('app.media.forest')) 220 .width('90%') 221 .height('80%') 222 .objectFit(ImageFit.Fill) 223 .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 224 .margin(30) 225 226 Row({ space: 10 }) { 227 Button("pushUrl") 228 .onClick(() => { 229 // 路由到下一页面,push操作 230 router.pushUrl({ url: 'pages/myTest/pageTransitionSrc1' }); 231 }) 232 Button("back") 233 .onClick(() => { 234 // 返回到上一页面,相当于pop操作 235 router.back(); 236 }) 237 }.justifyContent(FlexAlign.Center) 238 } 239 .width("100%").height("100%") 240 .alignItems(HorizontalAlign.Center) 241 } 242 243 pageTransition() { 244 // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效 245 PageTransitionEnter({ type: RouteType.Push, duration: 1000 }) 246 .slide(SlideEffect.Right) 247 // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效 248 PageTransitionEnter({ type: RouteType.Pop, duration: 1000 }) 249 .slide(SlideEffect.Left) 250 // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效 251 PageTransitionExit({ type: RouteType.Push, duration: 1000 }) 252 .slide(SlideEffect.Left) 253 // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效 254 PageTransitionExit({ type: RouteType.Pop, duration: 1000 }) 255 .slide(SlideEffect.Right) 256 } 257} 258``` 259 260 261 262![pageTransition_PushPop](figures/pageTransition_PushPop.gif) 263 264 265下面介绍使用了type为None的页面转场动画示例。 266 267 268 269```ts 270// page A 271import router from '@ohos.router'; 272@Entry 273@Component 274struct PageTransitionSrc2 { 275 build() { 276 Column() { 277 Image($r('app.media.mountain')) 278 .width('90%') 279 .height('80%') 280 .objectFit(ImageFit.Fill) 281 .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 282 .margin(30) 283 284 Row({ space: 10 }) { 285 Button("pushUrl") 286 .onClick(() => { 287 // 路由到下一页面,push操作 288 router.pushUrl({ url: 'pages/myTest/pageTransitionDst2' }); 289 }) 290 Button("back") 291 .onClick(() => { 292 // 返回到上一页面,相当于pop操作 293 router.back(); 294 }) 295 }.justifyContent(FlexAlign.Center) 296 } 297 .width("100%").height("100%") 298 .alignItems(HorizontalAlign.Center) 299 } 300 301 pageTransition() { 302 // 定义页面进入时的效果,从左侧滑入,时长为1000ms,无论页面栈发生push还是pop操作均可生效 303 PageTransitionEnter({ duration: 1000 }) 304 .slide(SlideEffect.Left) 305 // 定义页面退出时的效果,相对于正常页面位置x方向平移100vp,y方向平移100vp,透明度变为0,时长为1200ms,无论页面栈发生push还是pop操作均可生效 306 PageTransitionExit({ duration: 1200 }) 307 .translate({ x: 100.0, y: 100.0 }) 308 .opacity(0) 309 } 310} 311``` 312 313 314 315```ts 316// page B 317import router from '@ohos.router'; 318@Entry 319@Component 320struct PageTransitionDst2 { 321 build() { 322 Column() { 323 Image($r('app.media.forest')) 324 .width('90%') 325 .height('80%') 326 .objectFit(ImageFit.Fill) 327 .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成 328 .margin(30) 329 330 Row({ space: 10 }) { 331 Button("pushUrl") 332 .onClick(() => { 333 // 路由到下一页面,push操作 334 router.pushUrl({ url: 'pages/myTest/pageTransitionSrc2' }); 335 }) 336 Button("back") 337 .onClick(() => { 338 // 返回到上一页面,相当于pop操作 339 router.back(); 340 }) 341 }.justifyContent(FlexAlign.Center) 342 } 343 .width("100%").height("100%") 344 .alignItems(HorizontalAlign.Center) 345 } 346 347 pageTransition() { 348 // 定义页面进入时的效果,从左侧滑入,时长为1200ms,无论页面栈发生push还是pop操作均可生效 349 PageTransitionEnter({ duration: 1200 }) 350 .slide(SlideEffect.Left) 351 // 定义页面退出时的效果,相对于正常页面位置x方向平移100vp,y方向平移100vp,透明度变为0,时长为1000ms,无论页面栈发生push还是pop操作均可生效 352 PageTransitionExit({ duration: 1000 }) 353 .translate({ x: 100.0, y: 100.0 }) 354 .opacity(0) 355 } 356} 357``` 358 359 360 361![pageTransition_None](figures/pageTransition_None.gif) 362