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

发布于 1周前 作者 nodeper 来自 鸿蒙OS

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

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

2 回复

可以参考如下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
      })
    }
}

更多关于HarmonyOS 鸿蒙Next 如何实现新页面从下往上打开的页面转场动画效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next系统中,实现新页面从下往上打开的页面转场动画效果,可以通过自定义动画资源并在页面跳转时应用该动画资源来实现。

首先,需要在resources/anim目录下创建两个动画资源文件:slide_in_from_bottom.xmlslide_out_to_top.xmlslide_in_from_bottom.xml定义新页面从底部滑入的动画,而slide_out_to_top.xml定义旧页面滑出到顶部的动画。

例如,slide_in_from_bottom.xml内容可以如下:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromYDelta="100%"
        android:toYDelta="0%" />
</set>

在代码中,当需要跳转到新页面时,可以通过IntentPageOptions来设置动画资源。例如:

Intent intent = new Intent(this, NewPage.class);
PageOptions options = new PageOptions();
options.setEnterAnimResId(ResourceTable.Animation_slide_in_from_bottom);
options.setExitAnimResId(ResourceTable.Animation_slide_out_to_top);
startAbility(intent, options);

注意,这里的代码示例仅用于说明如何设置动画资源,实际在鸿蒙开发中,动画资源的设置和页面跳转的方式可能有所不同,需根据鸿蒙API文档进行适当调整。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部