鸿蒙开发笔记(二十五):动画--页面间的动画

1. 放大缩小视图

在不同页面间,有使用相同的元素(例如同一幅图)的场景,可以使用共享元素转场动画衔接。为了突出不同页面间相同元素的关联性,可为它们添加共享元素转场动画。如果相同元素在不同页面间的大小有明显差异,即可达到放大缩小视图的效果。

共享元素转场的接口为:

sharedTransition(id: string, options?: sharedTransitionOptions)

其中根据sharedTransitionOptions中的type参数,共享元素转场分为Exchange类型的共享元素转场和Static类型的共享元素转场。

1.1 Exchange类型的共享元素转场

交换型的共享元素转场,需要两个页面中,存在通过sharedTransition函数配置为相同id的组件,它们称为共享元素。这种类型的共享元素转场适用于两个页面间相同元素的衔接,会从起始页共享元素的位置、大小过渡到目标页的共享元素的位置、大小。如果不指定type,默认为Exchange类型的共享元素转场,这也是最常见的共享元素转场的方式。使用Exchange类型的共享元素转场时,共享元素转场的动画参数由目标页options中的动画参数决定。

1.2 Static类型的共享元素转场

静态型的共享元素转场通常用于页面跳转时,标题逐渐出现或隐藏的场景,只需要在一个页面中有Static的共享元素,不能在两个页面中出现相同id的Static类型的共享元素。在跳转到该页面(即目标页)时,配置Static类型sharedTransition的组件做透明度从0到该组件设定的透明度的动画,位置保持不变。在该页面(即起始页)消失时,做透明度逐渐变为0的动画,位置保持不变。

共享元素转场的动画参数由该组件sharedTransition属性中的动画参数决定。

1.3 场景示例

下面介绍使用共享元素转场进行放大缩小图片的示例。

// src page
import router from '@ohos.router';

@Entry
@Component
struct SharedTransitionSrc {
  build() {
    Column() {
      // 配置Exchange类型的共享元素转场,共享元素id为"sharedImage1"
      Image($r('app.media.mountain')).width(50).height(50)
        .sharedTransition('sharedImage1', { duration: 1000, curve: Curve.Linear })
        .onClick(() => {
          // 点击小图时路由跳转至下一页面
          router.pushUrl({ url: 'pages/myTest/sharedTransitionDst' });
        })
    }
    .padding(10)
    .width("100%")
    .alignItems(HorizontalAlign.Start)
  }
}
// dest page
import router from '@ohos.router';
@Entry
@Component
struct SharedTransitionDest {
  build() {
    Column() {
      // 配置Static类型的共享元素转场
      Text("SharedTransition dest page")
        .fontSize(16)
        .sharedTransition('text', { duration: 500, curve: Curve.Linear, type: SharedTransitionEffectType.Static })
        .margin({ top: 10 })

      // 配置Exchange类型的共享元素转场,共享元素id为"sharedImage1"
      Image($r('app.media.mountain'))
        .width(150)
        .height(150)
        .sharedTransition('sharedImage1', { duration: 500, curve: Curve.Linear })
        .onClick(() => {
          // 点击图片时路由返回至上一页面
          router.back();
        })
    }
    .width("100%")
    .alignItems(HorizontalAlign.Center)
  }
}

上述示例中,第一个页面(src page)和第二个页面(dest page)都配置了id为"sharedImage1"的共享元素转场,使两个页面能匹配到这一组共享元素。从第一个页面跳转到第二个页面时,第一个页面为起始页,第二个页面为目标页。配置id为"sharedImage1"的组件按照目标页中500ms的时长进行共享元素转场,达到放大视图的效果,id为"text"的组件按照配置的Static类型sharedTransition参数中的500ms的时长进行共享元素转场,标题逐渐出现。从第二个页面返回到第一个页面时,第二个页面为起始页,第一个页面为目标页。配置id为"sharedImage1"的组件按照目标页中1000ms的时长进行共享元素转场,缩小为原始视图,id为"text"的组件按照配置的Static类型sharedTransition参数中的500ms的时长进行共享元素转场,标题逐渐隐藏。
在这里插入图片描述

2. 页面转场动画

两个页面间发生跳转,一个页面消失,另一个页面出现,这时可以配置各自页面的页面转场参数实现自定义的页面转场效果。页面转场效果写在pageTransition函数中,通过PageTransitionEnter和PageTransitionExit指定页面进入和退出的动画效果。

PageTransitionEnter的接口为:

PageTransitionEnter({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number})

PageTransitionExit的接口为:

PageTransitionExit({type?: RouteType,duration?: number,curve?: Curve | string,delay?: number})

上述接口定义了PageTransitionEnter和PageTransitionExit组件,可通过slide、translate、scale、opacity属性定义不同的页面转场效果。对于PageTransitionEnter而言,这些效果表示入场时起点值,对于PageTransitionExit而言,这些效果表示退场的终点值,这一点与组件转场transition配置方法类似。此外,PageTransitionEnter提供了onEnter接口进行自定义页面入场动画的回调,PageTransitionExit提供了onExit接口进行自定义页面退场动画的回调。

上述接口中的参数type,表示路由生效的类型,这一点开发者容易混淆其含义。页面转场的两个页面,必定有一个页面退出,一个页面进入。如果通过router.pushUrl操作从页面A跳转到页面B,则页面A退出,做页面退场动画,页面B进入,做页面入场动画。如果通过router.back操作从页面B返回到页面A,则页面B退出,做页面退场动画,页面A进入,做页面入场动画。即页面的PageTransitionEnter既可能是由于新增页面(push,入栈)引起的新页面的入场动画,也可能是由于页面返回(back,或pop,出栈)引起的页面栈中老页面的入场动画,为了能区分这两种形式的入场动画,提供了type参数,这样开发者能完全定义所有类型的页面转场效果。

2.1 type配置为RouteType.None

type为RouteType.None表示对页面栈的push、pop操作均生效,type的默认值为RouteType.None。

// page A
pageTransition() {
  // 定义页面进入时的效果,从左侧滑入,时长为1200ms,无论页面栈发生push还是pop操作均可生效
  PageTransitionEnter({ type: RouteType.None, duration: 1200 })
    .slide(SlideEffect.Left)
  // 定义页面退出时的效果,向左侧滑出,时长为1000ms,无论页面栈发生push还是pop操作均可生效
  PageTransitionExit({ type: RouteType.None, duration: 1000 })
    .slide(SlideEffect.Left)
}
// page B
pageTransition() {
  // 定义页面进入时的效果,从右侧滑入,时长为1000ms,无论页面栈发生push还是pop操作均可生效
  PageTransitionEnter({ type: RouteType.None, duration: 1000 })
    .slide(SlideEffect.Right)
  // 定义页面退出时的效果,向右侧滑出,时长为1200ms,无论页面栈发生push还是pop操作均可生效
  PageTransitionExit({ type: RouteType.None, duration: 1200 })
    .slide(SlideEffect.Right)
}

假设页面栈为标准实例模式,即页面栈中允许存在重复的页面。可能会有4种场景,对应的页面转场效果如下表。
在这里插入图片描述
如果希望pushUrl进入的页面总是从右侧滑入,back时退出的页面总是从右侧滑出,则上表中的第3、4种情况不满足要求,那么需要完整的定义4个页面转场效果。

2.2 type配置为RouteType.Push或RouteType.Pop

type为RouteType.Push表示仅对页面栈的push操作生效,type为RouteType.Pop表示仅对页面栈的pop操作生效。

// page A
pageTransition() {
  // 定义页面进入时的效果,从右侧滑入,时长为1200ms,页面栈发生push操作时该效果才生效
  PageTransitionEnter({ type: RouteType.Push, duration: 1200 })
    .slide(SlideEffect.Right)
  // 定义页面进入时的效果,从左侧滑入,时长为1200ms,页面栈发生pop操作时该效果才生效
  PageTransitionEnter({ type: RouteType.Pop, duration: 1200 })
    .slide(SlideEffect.Left)
  // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效
  PageTransitionExit({ type: RouteType.Push, duration: 1000 })
    .slide(SlideEffect.Left)
  // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效
  PageTransitionExit({ type: RouteType.Pop, duration: 1000 })
    .slide(SlideEffect.Right)
}
// page B
pageTransition() {
  // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效
  PageTransitionEnter({ type: RouteType.Push, duration: 1000 })
    .slide(SlideEffect.Right)
  // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效
  PageTransitionEnter({ type: RouteType.Pop, duration: 1000 })
    .slide(SlideEffect.Left)
  // 定义页面退出时的效果,向左侧滑出,时长为1200ms,页面栈发生push操作时该效果才生效
  PageTransitionExit({ type: RouteType.Push, duration: 1200 })
    .slide(SlideEffect.Left)
  // 定义页面退出时的效果,向右侧滑出,时长为1200ms,页面栈发生pop操作时该效果才生效
  PageTransitionExit({ type: RouteType.Pop, duration: 1200 })
    .slide(SlideEffect.Right)
}

以上代码则完整的定义了所有可能的页面转场样式。假设页面栈为标准实例模式,即页面栈中允许存在重复的页面。可能会有4种场景,对应的页面转场效果如下表。
在这里插入图片描述

  1. 由于每个页面的页面转场样式都可由开发者独立配置,而页面转场涉及到两个页面,开发者应考虑两个页面的页面转场效果的衔接,如时长尽量保持一致。

  2. 如果没有定义匹配的页面转场样式,则该页面使用系统默认的页面转场样式。

3.3 禁用某页面的页面转场

pageTransition() {
  PageTransitionEnter({ type: RouteType.None, duration: 0 })
  PageTransitionExit({ type: RouteType.None, duration: 0 })
}

通过设置页面转场的时长为0,可使该页面无页面转场动画。

3.4 场景示例

下面介绍定义了所有的四种页面转场样式的页面转场动画示例。

// PageTransitionSrc1
import router from '@ohos.router';
@Entry
@Component
struct PageTransitionSrc1 {
  build() {
    Column() {
      Image($r('app.media.mountain'))
        .width('90%')
        .height('80%')
        .objectFit(ImageFit.Fill)
        .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成
        .margin(30)

      Row({ space: 10 }) {
        Button("pushUrl")
          .onClick(() => {
            // 路由到下一个页面,push操作
            router.pushUrl({ url: 'pages/myTest/pageTransitionDst1' });
          })
        Button("back")
          .onClick(() => {
            // 返回到上一页面,相当于pop操作
            router.back();
          })
      }.justifyContent(FlexAlign.Center)
    }
    .width("100%").height("100%")
    .alignItems(HorizontalAlign.Center)
  }
  pageTransition() {
    // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效
    PageTransitionEnter({ type: RouteType.Push, duration: 1000 })
      .slide(SlideEffect.Right)
    // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效
    PageTransitionEnter({ type: RouteType.Pop, duration: 1000 })
      .slide(SlideEffect.Left)
    // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效
    PageTransitionExit({ type: RouteType.Push, duration: 1000 })
      .slide(SlideEffect.Left)
    // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效
    PageTransitionExit({ type: RouteType.Pop, duration: 1000 })
      .slide(SlideEffect.Right)
  }
}
// PageTransitionDst1
import router from '@ohos.router';
@Entry
@Component
struct PageTransitionDst1 {
  build() {
    Column() {
      Image($r('app.media.forest'))
        .width('90%')
        .height('80%')
        .objectFit(ImageFit.Fill)
        .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成
        .margin(30)

      Row({ space: 10 }) {
        Button("pushUrl")
          .onClick(() => {
            // 路由到下一页面,push操作
            router.pushUrl({ url: 'pages/myTest/pageTransitionSrc1' });
          })
        Button("back")
          .onClick(() => {
            // 返回到上一页面,相当于pop操作
            router.back();
          })
      }.justifyContent(FlexAlign.Center)
    }
    .width("100%").height("100%")
    .alignItems(HorizontalAlign.Center)
  }
  pageTransition() {
    // 定义页面进入时的效果,从右侧滑入,时长为1000ms,页面栈发生push操作时该效果才生效
    PageTransitionEnter({ type: RouteType.Push, duration: 1000 })
      .slide(SlideEffect.Right)
    // 定义页面进入时的效果,从左侧滑入,时长为1000ms,页面栈发生pop操作时该效果才生效
    PageTransitionEnter({ type: RouteType.Pop, duration: 1000 })
      .slide(SlideEffect.Left)
    // 定义页面退出时的效果,向左侧滑出,时长为1000ms,页面栈发生push操作时该效果才生效
    PageTransitionExit({ type: RouteType.Push, duration: 1000 })
      .slide(SlideEffect.Left)
    // 定义页面退出时的效果,向右侧滑出,时长为1000ms,页面栈发生pop操作时该效果才生效
    PageTransitionExit({ type: RouteType.Pop, duration: 1000 })
      .slide(SlideEffect.Right)
  }
}

下面介绍使用了type为None的页面转场动画示例。

// PageTransitionSrc2
import router from '@ohos.router';
@Entry
@Component
struct PageTransitionSrc2 {
  build() {
    Column() {
      Image($r('app.media.mountain'))
        .width('90%')
        .height('80%')
        .objectFit(ImageFit.Fill)
        .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成
        .margin(30)

      Row({ space: 10 }) {
        Button("pushUrl")
          .onClick(() => {
            // 路由到下一页面,push操作
            router.pushUrl({ url: 'pages/myTest/pageTransitionDst2' });
          })
        Button("back")
          .onClick(() => {
            // 返回到上一页面,相当于pop操作
            router.back();
          })
      }.justifyContent(FlexAlign.Center)
    }
    .width("100%").height("100%")
    .alignItems(HorizontalAlign.Center)
  }
  pageTransition() {
    // 定义页面进入时的效果,从左侧滑入,时长为1000ms,无论页面栈发生push还是pop操作均可生效
    PageTransitionEnter({ duration: 1000 })
      .slide(SlideEffect.Left)
    // 定义页面退出时的效果,相对于正常页面位置x方向平移100vp,y方向平移100vp,透明度变为0,时长为1200ms,无论页面栈发生push还是pop操作均可生效
    PageTransitionExit({ duration: 1200 })
      .translate({ x: 100.0, y: 100.0 })
      .opacity(0)
  }
}
// PageTransitionDst2
import router from '@ohos.router';
@Entry
@Component
struct PageTransitionDst2 {
  build() {
    Column() {
      Image($r('app.media.forest'))
        .width('90%')
        .height('80%')
        .objectFit(ImageFit.Fill)
        .syncLoad(true) // 同步加载图片,使页面出现时图片已经加载完成
        .margin(30)

      Row({ space: 10 }) {
        Button("pushUrl")
          .onClick(() => {
            // 路由到下一页面,push操作
            router.pushUrl({ url: 'pages/myTest/pageTransitionSrc2' });
          })
        Button("back")
          .onClick(() => {
            // 返回到上一页面,相当于pop操作
            router.back();
          })
      }.justifyContent(FlexAlign.Center)
    }
    .width("100%").height("100%")
    .alignItems(HorizontalAlign.Center)
  }
  pageTransition() {
    // 定义页面进入时的效果,从左侧滑入,时长为1200ms,无论页面栈发生push还是pop操作均可生效
    PageTransitionEnter({ duration: 1200 })
      .slide(SlideEffect.Left)
    // 定义页面退出时的效果,相对于正常页面位置x方向平移100vp,y方向平移100vp,透明度变为0,时长为1000ms,无论页面栈发生push还是pop操作均可生效
    PageTransitionExit({ duration: 1000 })
      .translate({ x: 100.0, y: 100.0 })
      .opacity(0)
  }
}
  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值