HarmonyOS navigation导航转场动画怎么写

我路由用的navagtion想知道从一个页面跳转到另外一个页面的动画怎么写,比如我页面1 打开页面2 ,页面2 从底部弹出

HarmonyOS
2024-12-25 08:47:28
864浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
Heiang

转场动画demo请参考:

// Index.ets
import { CustomTransition, AnimateCallback } from './CustomNavigationUtils'
import { pageOneTmp } from './PageOne'
import {PageTwoTemp} from './PageTwo'

@Entry
@Component
struct NavigationExample {
  @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()

  @Builder
  PageMap(name: string) {
    if (name === 'pageOne') {

      pageOneTmp({pageId: Date.now()})
    } else if (name === 'pageTwo') {
      PageTwoTemp({pageId: Date.now()})
    }
  }

  aboutToAppear() {
    if (this.pageInfos === undefined) {
      this.pageInfos = new NavPathStack();
    }
    this.pageInfos.pushPath({name: 'pageOne'}, false)
  }

  build() {
    Navigation(this.pageInfos) {
    }.title('NavIndex').navDestination(this.PageMap)
    .hideNavBar(true)
    .customNavContentTransition((from: NavContentInfo, to: NavContentInfo, operation: NavigationOperation) => {
      if (from.mode == NavDestinationMode.DIALOG || to.mode == NavDestinationMode.DIALOG) {
        return undefined;
      }
      console.log(`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) {
        console.log("undefined")
        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");
          let fromParam: AnimateCallback = CustomTransition.getInstance()?.getAnimateParam(from.index);
          let toParam: AnimateCallback = CustomTransition.getInstance()?.getAnimateParam(to.index);
          if (fromParam.start != undefined) {
            console.log("fromParam.start");
            // push, x = 0
            fromParam.start(operation == NavigationOperation.PUSH, true);
          }
          if (toParam.start != undefined) {
            console.log("toParam.start");
            // push, x = 300
            toParam.start(operation == NavigationOperation.PUSH, false);
          }
          animateTo({duration: 1200, onFinish: ()=>{
            console.log("animateTo start");
            if (fromParam.onFinish != undefined) {
              console.log("fromParam onFinish");
              //  push 0
              fromParam.onFinish(operation === NavigationOperation.PUSH, true);
            }
            if (toParam.onFinish != undefined) {
              console.log("toParam onFinish");
              //  push 0
              toParam.onFinish(operation === NavigationOperation.PUSH, false);
            }
            transitionProxy.finishTransition();
          }}, ()=>{
            if (fromParam.finish != undefined) {
              console.log("fromParam finish");
              // push x = -300
              fromParam?.finish(operation === NavigationOperation.PUSH, true)
            }
            if (toParam.finish != undefined) {
              console.log("toParam finish");
              // push x = 0
              toParam?.finish(operation === NavigationOperation.PUSH, false);
            }
          })
        }
      };
      return customAnimation;
    })
  }
}


import {CustomTransition} from './CustomNavigationUtils'

@Component
export struct pageOneTmp {
  @Consume('pageInfos') pageInfos: NavPathStack
  @State x: number = 0
  @State scaleVal: number = 1
  pageId: number = 0;

  aboutToAppear() {
    this.pageId = this.pageInfos.getAllPathName().length - 1;
    CustomTransition.getInstance().registerNavParam(this.pageId, (isPush: boolean, isExit: boolean) => {
      this.x = isExit ? 0 : 300;
    }, (isPush: boolean, isExit: boolean)=> {
      this.x = isExit ? -300 : 0;
    }, (isPush: boolean, isExit: boolean) => {
      console.log("PageTwo x finish : " + this.x)
      this.x = 0;
    }, 200);
  }

  build() {
    NavDestination() {
      Column() {
        Button('pageTwo', { stateEffect: true, type: ButtonType.Capsule })
          .width('80%')
          .height(40)
          .margin(20)
          .onClick(() => {
            this.pageInfos.pushPathByName('pageTwo', null) //将name指定的NavDestination页面信息入栈,传递的数据为param
          })
        Button('pageOne', { stateEffect: true, type: ButtonType.Capsule })
          .width('80%')
          .height(40)
          .margin(20)
          .onClick(() => {
            this.pageInfos.pushPathByName('pageOne', null) //将name指定的NavDestination页面信息入栈,传递的数据为param
          })
      }.width('100%').height('100%')
    }.title('pageOne')
    .mode(NavDestinationMode.STANDARD)
    .onBackPressed(() => {
      const popDestinationInfo = this.pageInfos.pop() // 弹出路由栈栈顶元素
      console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo))
      return true
    })
    .onDisAppear(()=>{
      console.log("pageone onDisAppear");
      CustomTransition.getInstance().unRegisterNavParam(this.pageId)
    })
    .translate({x: 0, y: this.x, z: 0})
    .backgroundColor(Color.White)
  }
}


import {CustomTransition} from './CustomNavigationUtils'

@Component
export struct PageTwoTemp {
  @Consume('pageInfos') pageInfos: NavPathStack
  @State x: number = 300
  pageId:number = 0;

  aboutToAppear() {
    this.pageId = this.pageInfos.getAllPathName().length - 1;
    CustomTransition.getInstance().registerNavParam(this.pageId, (isPush: boolean, isExit: boolean) => {
      this.x = isExit ? 0 : isPush ? 300 : -300;
      console.log("PageTwo x start is : " + this.x)
    }, (isPush: boolean, isExit: boolean)=> {
      this.x = isExit ? isPush ? -300 : 300 : 0;
      console.log("PageTwo x end is : " + this.x)
    }, (isPush: boolean, isExit: boolean) => {
      this.x = 0;
      console.log("PageTwo x finish : " + this.x)
    }, 2000);
  }

  build() {
    NavDestination() {
      Column() {
        Button('pushPathByName', { stateEffect: true, type: ButtonType.Capsule })
          .width('80%')
          .height(40)
          .margin(20)
          .onClick(() => {
            this.pageInfos.pushPathByName('pageOne', null) //将name指定的NavDestination页面信息入栈,传递的数据为param
          })
        Button('pageTwo', { stateEffect: true, type: ButtonType.Capsule })
          .width('80%')
          .height(40)
          .margin(20)
          .onClick(() => {
            this.pageInfos.pushPathByName('pageTwo', null) //将name指定的NavDestination页面信息入栈,传递的数据为param
          })
      }.width('100%').height('100%')
    }.title('pageTwo')
    .onBackPressed(() => {
      console.log("pagetwo onBackPressed");
      const popDestinationInfo = this.pageInfos.pop() // 弹出路由栈栈顶元素
      console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo))
      return true
    })
    .onDisAppear(()=>{
      console.log("pagetwo onDisAppear");
      CustomTransition.getInstance().unRegisterNavParam(this.pageId)
    })
    .opacity(0.5)
    .translate({x: 0, y: 0, z: this.x})
    .backgroundColor(Color.White)
  }
}


// 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;
}
const customTransitionMap: Map<number, AnimateCallback> = new Map()
export class CustomTransition {
  private constructor() {

  }

  static delegate = new CustomTransition();

  static getInstance() {
    return CustomTransition.delegate;
  }

  registerNavParam(name: number, startCallback: (operation: boolean, isExit: boolean) => void,
    endCallback:(operation: boolean, isExit: boolean) => void,
    onFinish: (opeation: boolean, isExit: boolean) => void, timeout: number): void {
    console.log("registerNavParam");
    if (customTransitionMap.has(name)) {
      let param = customTransitionMap.get(name);
      if (param != undefined) {
        param.start = startCallback;
        param.finish = endCallback;
        param.onFinish = onFinish;
        param.timeout = timeout;
        return;
      }
    }
    let params: AnimateCallback = {timeout: timeout, start: startCallback, finish: endCallback, onFinish: onFinish};
    customTransitionMap.set(name, params);
  }

  unRegisterNavParam(name: number): void {
    console.log("unRegisterNavParam");
    customTransitionMap.delete(name);
  }

  getAnimateParam(name: number): AnimateCallback {
    console.log("unRegisterNavParam");
    let result: AnimateCallback = {
      start: customTransitionMap.get(name)?.start,
      finish: customTransitionMap.get(name)?.finish,
      timeout: customTransitionMap.get(name)?.timeout,
      onFinish: customTransitionMap.get(name)?.onFinish
    };
    return result;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
分享
微博
QQ
微信
回复
2024-12-25 10:32:32
相关问题
HarmonyOS Navigation实现Dialog转场动画
712浏览 • 1回复 待解决
HarmonyOS Navigation转场动画的一些思路
717浏览 • 1回复 待解决
Navigation如何自定义立体转场动画
340浏览 • 1回复 待解决
HarmonyOS Navigation转场?
523浏览 • 0回复 待解决
救命,鸿蒙怎么动画
6593浏览 • 2回复 待解决
HarmonyOS Navigation导航
613浏览 • 1回复 待解决
HarmonyOS SideBarContainer 转场动画
551浏览 • 1回复 待解决
HarmonyOS 如何自定义导航转场
975浏览 • 1回复 待解决
如何实现动画转场效果
1782浏览 • 1回复 待解决
HarmonyOS Refresh和页面转场动画demo
668浏览 • 1回复 待解决
HarmonyOS 无感转场动画推荐方案
846浏览 • 1回复 待解决
HarmonyOS 页面内的组件转场动画
1095浏览 • 1回复 待解决
Tabs 出现/消失转场动画效果
1108浏览 • 1回复 待解决