HarmonyOS 如何实现新页面从下往上打开的页面转场动画效果?

项目里想要做一个从下往上打开效果的页面转场动画,但是看了这个例子,没看到哪里可以设置移动方向,望给予一个详细demo。目前不知道要如何实现。

阅读 459
1 个回答

从下往上打开效果的页面转场动画请参考如下demo

//Index.ets
import { promptAction } from '@kit.ArkUI';
import { Page01 } from '../components/Page01';
import { Page02 } from '../components/Page02';
import { Page03 } from '../components/Page03';
import { AnimateCallback, CustomTransition } from './CustomNavigationUtils';

export class Pages {
  names: string = ""
  values: NavPathStack | null = null
}
export const pagesUserName: Array<string> = ['Page01', 'Page02', 'Page03'];

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

  aboutToAppear(): void {
    // this.pageInfos.disableAnimation(true)
  }

  @Builder
  PageMap(name: string) {
    if (name==='Page01') {
      Page01()
    } else if (name==='Page02') {
      Page02()
    } else if (name==='Page03') {
      Page03()
    }

  }

  build() {
    Navigation(this.pageInfos) {
      Button('pushPath', {type: ButtonType.Capsule })
        .width('80%')
        .height(40)
        .margin(20)
        .onClick(() => {
          // 关闭入场动画
          // this.pageInfos.pushPathByName( 'Page01',null,false) 
          this.pageInfos.pushPathByName( 'Page01',null) //将name指定的NavDestination页面信息入栈
        })

    }.title('NavIndex').navDestination(this.PageMap)
    //转场协议对象
    .customNavContentTransition((from: NavContentInfo, to: NavContentInfo, operation: NavigationOperation) =>{
      // Push时,不需要播放来自页面的动画,因为它还在栈中
      let animateFormId: string = (from.name == null || operation == NavigationOperation.PUSH) ? 'null' : from.name;
      // Pop时,不需要播放去往页面的动画,因为它还在栈中
      let animateToId: string = (to.name == null || operation == NavigationOperation.POP) ? 'null' : to.name;
      // 如果两个页面都没有自定义动画,那么就播放默认动画
      if (!CustomTransition.getInstance().hasAnimateParam(animateFormId) &&
        !CustomTransition.getInstance().hasAnimateParam(animateToId)) {
        promptAction.showToast({ message: '没找到动画' });
        return undefined;
      }
      let customAnimation: NavigationAnimatedTransition = {
        onTransitionEnd: (isSuccess: boolean)=>{
        },
        // timeout: operation == NavigationOperation.REPLACE ? 2000 : 1000,
        //自定义的转场动画方法
        transition: (transitionProxy: NavigationTransitionProxy) => {
          let fromParam: AnimateCallback | undefined = CustomTransition.getInstance().getAnimateParam(animateFormId);
          let toParam: AnimateCallback | undefined = CustomTransition.getInstance().getAnimateParam(animateToId);
          fromParam?.start(operation == NavigationOperation.PUSH, true);
          toParam?.start(operation == NavigationOperation.PUSH, false);
          animateTo({
            duration: operation == NavigationOperation.REPLACE ? 2000 : 1000,
            onFinish: () => {
              //通知组件,此页面的自定义动画已结束
              transitionProxy.finishTransition();
            }}, () => {
            fromParam?.finish(operation === NavigationOperation.PUSH, true)
            toParam?.finish(operation === NavigationOperation.PUSH, false);
          })
        }
      };
      promptAction.showToast({ message: '播放动画' });
      return customAnimation;
    })

    .height('100%')
    .width('100%')
  }
}

//page01.ets
import { CustomTransition } from '../pages/CustomNavigationUtils';
import { Pages } from '../pages/Index';

@Component
export struct   Page01{

  @Consume('pageInfos') pageInfos: NavPathStack;
  @State translateY: string | number = 0;
  aboutToAppear() {
    // 注册动画
    CustomTransition.getInstance().registerTransitionParam("Page01", (isPush: boolean, isExit: boolean) => {
      // 开始时,若为入场,则
      this.translateY = isExit ? '0%' : '100%';
    }, (isPush: boolean, isExit: boolean) => {
      //出场
      this.translateY = isExit ? '100%' : '0%';
    }, 1000);
  }

  aboutToDisappear() {
    CustomTransition.getInstance().unregisterTransitionParam("Page01")
  }


  build(){
    NavDestination() {
      Column() {
        Button('pushPathByName', {  type: ButtonType.Capsule })
          .width('80%')
          .height(40)
          .margin(20)
          .onClick(() => {
            this.pageInfos.pushPathByName('Page02',null) //将name指定的NavDestination页面信息入栈,传递的数据为param
          })
      }.width('100%').height('100%')
    }.title('page01')
    .translate({x: 0, y: this.translateY})
    .onBackPressed(() => {
      //如返回的时候需要转场动画就把false去掉
      const popDestinationInfo = this.pageInfos.pop(false) // 弹出路由栈栈顶元素
      return true
    })
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进