HarmonyOS鸿蒙Next中navigation共享元素动画怎么实现类似android共享元素动画效果呢

HarmonyOS鸿蒙Next中navigation共享元素动画怎么实现类似android共享元素动画效果呢 目前Harmony有两个页面:Index 、Second, 通过Navigation导航从Index页面跳转到Second页面,其中共享元素是个Image组件,有设置了共享元素动画,但是共享元素的效果远远不如android的共享元素动画效果,android的共享元素效果很丝滑,Harmony的共享元素效果是明显有个先翻页后显示共享元素的过程, 返回上一页也是很坚硬,远远不如android的共享元素效果,要想实现像下面录屏展示的android那个共享元素效果需要怎么做呢?

Index页面代码:

@Entry
@ComponentV2
struct Index {
  @Provider('sswlPathStack') pathStack: NavPathStack = new NavPathStack()
  build() {
    Navigation(this.pathStack){
      Column() {
        //头像
        Image($r('app.media.a256'))
          .width(60)
          .height(60)
          .geometryTransition('avatar', { follow: true })
          // transition保证组件离场不被立即析构,可设置其他转场效果
          .transition(TransitionEffect.OPACITY)
          .onClick(() => {
            //共享元素动画
            this.getUIContext()?.animateTo({ duration: 500, curve: Curve.Sharp}, () => {
              this.pathStack.pushDestination({name:'second'}, false)
            })
          })
      }
      .justifyContent(FlexAlign.Start)
      .alignItems(HorizontalAlign.Start)
      .height('100%')
      .width('100%')
    }
    .backgroundColor(Color.Pink)

  }
}

Second页面代码:

@ComponentV2
struct Second {
  @Consumer('sswlPathStack') pathStack: NavPathStack = new NavPathStack()

  build() {
    NavDestination(){
      Column() {
        //头像
        Image($r('app.media.a256'))
          .width(150)
          .height(150)
          .geometryTransition('avatar', { follow: true })
          // transition保证组件离场不被立即析构,可设置其他转场效果
          .transition(TransitionEffect.OPACITY)
          .onClick(() => {
            this.getUIContext()?.animateTo({ duration: 800, curve: Curve.Friction}, () => {
              this.pathStack.pop()
            })
          })

        Text('点击头像')
          .fontSize(20)
      }
      .justifyContent(FlexAlign.Center)
      .height('100%')
      .width('100%')
    }
    .hideTitleBar(true)
    .hideToolBar(true)
    .backgroundColor(Color.Grey)
    .transition(TransitionEffect.OPACITY)
  }
}

@Builder
function SecondBuilder(){
  Second()
}

android的共享动画效果录屏:

android的共享动画效果录屏

Harmony共享元素动画效果:

Harmony共享元素动画效果


更多关于HarmonyOS鸿蒙Next中navigation共享元素动画怎么实现类似android共享元素动画效果呢的实战教程也可以访问 https://www.itying.com/category-93-b0.html

13 回复

这个是因为共享元素只支持在NavDestination之间使用,你出现这个情况是因为一个使用了Navigation,一个是NavDestination,解决方法是,页面一进入就直接进入一个NavDestination

aboutToAppear(): void {
this.pageInfos.pushPath({ name: RouterUrlConstants.HOME })
}

更多关于HarmonyOS鸿蒙Next中navigation共享元素动画怎么实现类似android共享元素动画效果呢的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


@Entry
@Component
struct Index {
  private uiContext = this.getUIContext() as UIContext;

  build() {
    Column() {
      Image($r('app.media.bg_fish'))
        .width(60)
        .height(60)
        .sharedTransition('imageTransition', { duration: 400, curve: Curve.EaseOut })
        .onClick(() => {
          this.uiContext.getRouter().pushUrl({
            url: 'pages/SecondPage'
          })
        })

    }
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Start)
    .height('100%')
    .width('100%')
    .backgroundColor(Color.Pink)
  }
}
@Entry
@Component
struct Detail {
  private uiContext = this.getUIContext() as UIContext;

  build() {
    Column() {

      Image($r('app.media.bg_fish'))
        .width(150)
        .height(150)
        .sharedTransition('imageTransition', { duration: 400, curve: Curve.EaseOut })

        .onClick(() => {
          this.uiContext.getRouter().back();
        })
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
    .backgroundColor(Color.Grey)

  }
}

我这边的导航都是统一用了navigation进行导航的哦,没用router了,

共享元素只支持在NavDestination之间使用,看下三楼我的回答呢。

Navigation组件内写入的Image不属于路由栈内元素,需确保Image是导航栈内的一部分,以便正确应用转场动画。 代码方案如下:

navigation根页面:

@Entry
@Component
struct Index {
  @Provide('navPS') navPathStack: NavPathStack = new NavPathStack();

  aboutToAppear(): void {
    this.navPathStack.replacePath({ name: 'nextB' }, false)
  }

  @Builder
  navPathMapBuilder(name: string) {
    if (name === 'nextB') {
      NextB()
    } else if (name === 'nextC') {
      NextC()
    }
  }

  build() {
    Navigation(this.navPathStack)
      .navDestination(this.navPathMapBuilder)
      .hideNavBar(true)
  }
}

页面B:

@Component
struct NextB {
  @Consume('navPS') navPathStack: NavPathStack

  build() {
    NavDestination() {
      Column() {
        Image($r('app.media.app_icon'))
          .width(80)
          .height(80)
          .geometryTransition('sharedId')
          .onClick(() => {
            animateTo({ duration: 1000 }, () => {
              this.navPathStack.pushPath({ name: 'nextC' }, false)
            })
          })
      }
      .width('100%')
      .height('100%')
    }
    .title('设置')
  }
}

页面C:

@Component
struct NextC {
  @Consume('navPS') navPathStack: NavPathStack

  build() {
    NavDestination() {
      Column() {
        Image($r('app.media.app_icon'))
          .width(160)
          .height(160)
          .geometryTransition('sharedId')
          .onClick(() => {
            animateTo({ duration: 1000 }, () => {
              this.navPathStack.pop(false)
            })
          })
      }
      .width('100%')
      .height('100%')
    }
    .title('Page C')
    .onBackPressed(() => {
      animateTo({ duration: 1000 }, () => {
        this.navPathStack.pop(false)
      })
      return true
    })
  }
}

请问你写的 this.navPathStack.pushPath({ name: 'nextC' }, false)this.navPathStack.pop(false) 后面的 false 是干啥的?

升级HarmonyOS后,发现手机的游戏性能也有了显著提升。

确实是这样,

这个是关闭默认跳转动画,

上面的arkts代码就是用了共享元素转场的实现的,但是没有达到android那么丝滑的效果,

在HarmonyOS Next中,可通过SharedTransition组件实现共享元素动画。在源页面和目标页面中,为需要共享的组件分别设置相同的sharedTransitionName。系统将自动识别并执行平滑的过渡动画。

在HarmonyOS Next中实现更流畅的共享元素动画,关键在于控制Navigation的转场效果,使其与共享元素动画同步。当前代码的问题在于Navigation默认的页面切换动画(如翻页效果)与共享元素动画分离,导致不连贯。

以下是优化方案:

  1. 禁用Navigation默认转场:为NavDestination设置.transition(TransitionEffect.NONE),避免页面切换动画干扰。

    .transition(TransitionEffect.NONE)
    
  2. 统一动画控制:将页面跳转和返回操作封装在animateTo中,确保共享元素动画与页面过渡同步。调整动画曲线(如Curve.Ease)和时长,使过渡更自然。

  3. 优化Second页面:确保共享元素Image的geometryTransition参数一致,并移除可能冲突的过渡效果。

修改后的核心代码示例

  • Index页面:跳转时使用animateTo控制导航。
  • Second页面:设置NavDestination的transition为NONE,返回时同样使用animateTo

这样调整后,共享元素动画将主导页面切换过程,消除“先翻页后显示”的割裂感,实现类似Android的丝滑效果。注意动画时长和曲线需根据实际效果微调。

回到顶部