参考示例如下:// Navigation.ets import { AnimateCallback, CustomTransition } from './CustomNavigationUtils' import { PageOne } from './PageOne' import { PageTwo } from './PageTwo' import { PageThree } from './PageThree' @Entry @Component struct NavigationExample { @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack() aboutToAppear() { if (this.pageInfos === undefined) { this.pageInfos = new NavPathStack(); } this.pageInfos.pushPath({ name: 'pageOne' }, false) } @Builder pageMapBuilder(name: string) { if (name === 'pageOne') { PageOne({ pageId: Date.now() }) } else if (name === 'pageTwo') { PageTwo({ pageId: Date.now() }) } else if (name === 'pageThree') { PageThree({ pageId: Date.now() }) } } setCustomAnimation(from: NavContentInfo, to: NavContentInfo, operation: NavigationOperation) { if (from.mode === NavDestinationMode.DIALOG || to.mode === NavDestinationMode.DIALOG) { return undefined; } console.log(`current info: ${to.name}, index: ${to.index}, mode: ${to.mode}`); console.log(`pre info: ${from.name}, index: ${from.index}, mode: ${from.mode}`); console.log(`operation: ${operation}`) if (from.index === -1 || to.index === -1) { return undefined; } let customAnimation: NavigationAnimatedTransition = { onTransitionEnd: (isSuccess: boolean) => { console.log(`current transition result is ${isSuccess}`); }, timeout: 700, // 转场开始时系统调用该方法,并传入转场上下文代理对象 transition: (transitionProxy: NavigationTransitionProxy) => { console.log('trigger transition callback'); // 从封装类CustomTransition中根据子页面的序列获取对应的转场动画回调 let fromParam: AnimateCallback = CustomTransition.getInstance().getAnimateParam(from.index); let toParam: AnimateCallback = CustomTransition.getInstance().getAnimateParam(to.index); if (fromParam.start != undefined) { fromParam.start(operation === NavigationOperation.PUSH, true); } if (toParam.start != undefined) { toParam.start(operation === NavigationOperation.PUSH, false); } animateTo({ duration: toParam.duration, onFinish: () => { if (fromParam.onFinish != undefined) { fromParam.onFinish(operation === NavigationOperation.PUSH, true); } if (toParam.onFinish != undefined) { toParam.onFinish(operation === NavigationOperation.PUSH, true); } transitionProxy.finishTransition(); } }, () => { if (fromParam.finish != undefined) { fromParam.finish(operation === NavigationOperation.PUSH, true); } if (toParam.finish != undefined) { toParam.finish(operation === NavigationOperation.PUSH, false); } }) } }; return customAnimation; } build() { Navigation(this.pageInfos) { }.title('NavIndex').navDestination(this.pageMapBuilder) .hideNavBar(true) .customNavContentTransition((from: NavContentInfo, to: NavContentInfo, operation: NavigationOperation) => { return this.setCustomAnimation(from, to, operation) }) } }// PageOne.ets import { CustomTransition } from './CustomNavigationUtils' import { router } from '@kit.ArkUI' @Component export struct PageOne { @Consume('pageInfos') pageInfos: NavPathStack @State y: number = 0 pageId: number = 0; aboutToAppear() { this.pageId = this.pageInfos.getAllPathName().length - 1; CustomTransition.getInstance().registerNavParam(this.pageId, (isPush: boolean, isExit: boolean) => { }, (isPush: boolean, isExit: boolean) => { }, (_isPush: boolean, _isExit: boolean) => { }, 2000, 0) } build() { NavDestination() { Column() { Text('设置') Column() { Button('搜索设置项') .onClick(() => { this.pageInfos.pushPathByName('pageTwo', null) // 将name指定的NavDestination页面信息入栈 }) Column() .width('90%') .height(500) .backgroundColor(Color.Brown) } .translate({ x: 0, y: this.y }) }.width('100%').height('100%') } .title('pageOne') .mode(NavDestinationMode.STANDARD) .hideTitleBar(true) .onShown(() => { console.log('pageOne onShown this.y', this.y, JSON.stringify(this.pageInfos)) animateTo({ duration: 300 }, () => { this.y = 0 }) }) .onHidden(() => { console.log('pageOne onWillHide') this.y = 60 }) .onBackPressed(() => { // const popDestinationInfo = this.pageInfos.pop() // 弹出路由栈栈顶元素 router.back() // console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo)) return true }) .onDisAppear(() => { CustomTransition.getInstance().unRegisterNavParam(this.pageId) }) .backgroundColor(Color.Gray) } }// PageTwo.ets import { CustomTransition } from './CustomNavigationUtils' @Component export struct PageTwo { @Consume('pageInfos') pageInfos: NavPathStack @State x: number = 0 @State y: number | string = '10%' @State showText: string = '' @State isTempShow: boolean = false pageId: number = 0 private isBack: boolean = false private controller: TextInputController = new TextInputController() aboutToAppear() { this.pageId = this.pageInfos.getAllPathName().length - 1; console.log('this.pageInfos.getAllPathName()', JSON.stringify(this.pageInfos.getAllPathName())) CustomTransition.getInstance().registerNavParam(this.pageId, (isPush: boolean, isExit: boolean) => { }, (isPush: boolean, isExit: boolean) => { }, (_isPush: boolean, _isExit: boolean) => { }, 2000, 400) } build() { NavDestination() { Column({ space: 20 }) { TextInput({ text: $$this.showText, controller: this.controller }) .backgroundColor('#ffffff') .width('90%') .height(40) .id('username') .onChange((value: string) => { // 模拟设置项 if (value) { this.isTempShow = true } else { this.isTempShow = false } }) Text('模拟设置') .width('90%') .height(40) .border({ width: 1, radius: 20 }) .visibility(this.isTempShow ? Visibility.Visible : Visibility.None) .onClick(() => { this.pageInfos.pushPathByName('pageThree', null) //将name指定的NavDestination页面信息入栈,传递的数据为param }) } .width('100%') .height('100%') .translate({ x: 0, y: this.y }) } .title('动画0') .translate({ x: this.x, y: 0 }) .onWillShow(() => { animateTo({ duration: 300 }, () => { this.y = 0 }) }) .onWillHide(() => { if (this.isBack) { return } animateTo({ duration: 300, onFinish: () => { this.isBack = false } }, () => { this.x = -100 }) }) .onShown(() => { animateTo({ duration: 300 }, () => { this.x = 0 }) }) .onBackPressed(() => { this.isBack = true let popDestinationInfo = this.pageInfos.pop() // 弹出路由栈栈顶元素 console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo)) return true }) .onDisAppear(() => { CustomTransition.getInstance().unRegisterNavParam(this.pageId) }) .backgroundColor(Color.Yellow) } }// PageThree.ets import { CustomTransition } from './CustomNavigationUtils' @Component export struct PageThree { @Consume('pageInfos') pageInfos: NavPathStack @State x: number | string = 0 pageId: number = 0 aboutToAppear() { this.pageId = this.pageInfos.getAllPathName().length - 1; console.log('this.pageInfos.getAllPathName()', JSON.stringify(this.pageInfos.getAllPathName())) CustomTransition.getInstance().registerNavParam(this.pageId, (isPush: boolean, isExit: boolean) => { this.x = isExit ? 0 : isPush ? '100%' : '-100%'; }, (isPush: boolean, isExit: boolean) => { this.x = isExit ? isPush ? '-100%' : '100%' : 0; }, (_isPush: boolean, _isExit: boolean) => { this.x = 0; }, 2000, 400) } build() { NavDestination() { Column() { Text('动画1') .width('80%') .height(40) .margin(20) .textAlign(TextAlign.Center) }.width('100%').height('100%') } .title('动画1') .onBackPressed(() => { let popDestinationInfo = this.pageInfos.pop() // 弹出路由栈栈顶元素 console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo)) return true }) .onDisAppear(() => { CustomTransition.getInstance().unRegisterNavParam(this.pageId) }) .translate({ x: this.x, y: 0 }) .backgroundColor(Color.Yellow) } }// CustomNavigationUtils.ts // 自定义接口,用来保存某个页面相关的转场动画回调和参数 export interface AnimateCallback { finish: ((isPush: boolean, isExit: boolean) => void | undefined) | undefined; start: ((isPush: boolean, isExit: boolean) => void | undefined) | undefined; onFinish: ((isPush: boolean, isExit: boolean) => void | undefined) | undefined; timeout: (number | undefined) | undefined; duration: number; } let customTransitionMap: Map<number, AnimateCallback> = new Map() export class CustomTransition { static delegate = new CustomTransition(); private constructor() { } static getInstance(): CustomTransition { return CustomTransition.delegate; } // 注册某个页面的动画回调 // startCallback:用来设置动画开始时页面的状态 // endCallback:用来设置动画结束时页面的状态 // onFinish:用来执行动画结束后页面的其他操作 // timeout:转场结束的超时时间 registerNavParam(name: number, startCallback: (operation: boolean, isExit: boolean) => void, endCallback: (operation: boolean, isExit: boolean) => void, onFinish: (operation: boolean, isExit: boolean) => void, timeout: number, duration: number): void { if (customTransitionMap.has(name)) { let param = customTransitionMap.get(name); if (param != undefined) { param.start = startCallback; param.finish = endCallback; param.timeout = timeout; param.onFinish = onFinish; param.duration = duration; return; } } let params: AnimateCallback = { timeout: timeout, start: startCallback, finish: endCallback, onFinish: onFinish, duration: duration }; customTransitionMap.set(name, params); } unRegisterNavParam(name: number): void { customTransitionMap.delete(name); } getAnimateParam(name: number): AnimateCallback { let result: AnimateCallback = { start: customTransitionMap.get(name)?.start, finish: customTransitionMap.get(name)?.finish, timeout: customTransitionMap.get(name)?.timeout, onFinish: customTransitionMap.get(name)?.onFinish, duration: customTransitionMap.get(name)?.duration, }; return result; } } export class FlowFood { title: string content: string itemIndex: number constructor(title: string, content: string, itemIndex: number) { this.title = title this.content = content this.itemIndex = itemIndex } }
参考示例如下: