HarmonyOS 鸿蒙Next中共享元素

HarmonyOS 鸿蒙Next中共享元素

有时候会出现控件显示不全,大概四五次会出现一次

跳转前: cke_909.png

跳转后: cke_4306.png

偶尔出现问题的跳转后: cke_8790.png

代码:

首页:

Search({ placeholder: '搜索' })
  .id("searchCaseTitle")
  .focusOnTouch(false)
  .focusable(false)
  .enableKeyboardOnFocus(false)
  .backgroundColor('#E7E9E8')
  .width('100%')
  .height(43)
  .onClick(() => {
    animateTo({ duration: 800 }, () => {
      this.pathInfos.pushPathByName('PageElementShare02', null, false)
    });
  })
  .geometryTransition(this.geometryId, { follow: true })
  .backgroundColor('#E7E9E8')
  .borderRadius(10)

跳转页:

Row() {
  Image($r('sys.media.ohos_ic_public_arrow_left'))
    .width(36)
    .height(36)
    .transition(TransitionEffect.asymmetric(
      TransitionEffect.opacity(0)
        .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 200, delay: 150 }),
      TransitionEffect.opacity(0)
        .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 200 }),
    ))

  Search({ value: this.searchInput, placeholder: '搜索' })
    .id("searchCaseTitleContentCover")
    .searchButton('搜索', { fontSize: 16 })
    .geometryTransition('search',{follow : true})
    .defaultFocus(true)
    .enableKeyboardOnFocus(false)
    .backgroundColor('#E7E9E8')
    .onChange((value) => {
      this.searchInput = value;
    })
    .margin({ left: 10, right: 10 })
    .layoutWeight(1)
    .height(43)

}

版本 cke_17852.png


更多关于HarmonyOS 鸿蒙Next中共享元素的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

【背景知识】

  • 共享元素转场geometryTransition用于组件内的切换,在视图切换过程中提供丝滑的上下文传承过渡。通过绑定组件的进出状态(in指新视图、out指旧视图)来实现转场动画。它通过安排绑定的in/out组件的frame、position使得原本独立的transition动画在空间位置上发生联系,将视觉焦点由旧视图位置引导到新视图位置。这种方式区别于传统的opacity和scale转场效果,提供了更高的灵活性和创意空间。适用于一镜到底场景。必须配合animateTo使用才有动画效果。不支持animation隐式动画。

  • 共享元素转场 (sharedTransition)是一种在页面路由跳转时使用的过渡动画,其中特定的UI组件被标识为共享元素,并在页面跳转时展示转场动效。在相关的组件上设置sharedTransition属性,并指定相应的参数,确保在不同页面中使用的共享元素具有相同的ID值,来识别共享元素。特别适用于需要强调元素连续性的场景,如图库浏览,商品详情页等。仅发生在页面路由跳转时使用。

【问题定位】

通过上面的代码片段暂时没有复现该问题,但是通过代码分析geometryTransition共享元素用在了页面间的跳转,而geometryTransition用于的是组件间切换,可能引起显示问题。

【分析结论】

组件间切换使用geometryTransition,页面间切换使用共享元素转场 (sharedTransition)

【修改建议】

//Index.ets
@Entry
@Component
struct Index {
  @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack();
  build() {
    Navigation(this.pageInfos)
    {
      Search({ placeholder: '搜索' })
        .id("searchCaseTitle")
        .focusOnTouch(false)
        .focusable(false)
        .enableKeyboardOnFocus(false)
        .backgroundColor('#E7E9E8')
        .width('90%')
        .height(43)
        .onClick(() => {
          animateTo({ duration: 800 }, () => {
            this.pageInfos.pushPathByName('PageB', null, false)
          });
        })
        .sharedTransition('SEARCH_ONE_SHOT_DEMO_TRANSITION_ID', { duration: 800, curve: Curve.Linear, delay: 100 })
        .backgroundColor('#E7E9E8')
        .borderRadius(10)
    }
  }
}

//PageB.ets
import { curves } from "@kit.ArkUI";

@Builder
export function pageBBuilder() {
  pageBExample()
}

@Entry
@Component
struct pageBExample {
  @Consume('pageInfos') pageInfos: NavPathStack;
  @State searchInput: string = '';
  build() {
    NavDestination()
    {
      Row({ space: 8 }) {
        Image($r('sys.media.ohos_ic_public_arrow_left'))
          .width(36)
          .height(36)
          .transition(TransitionEffect.asymmetric(
            TransitionEffect.opacity(0)
              .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 200, delay: 150 }),
            TransitionEffect.opacity(0)
              .animation({ curve: curves.cubicBezierCurve(0.33, 0, 0.67, 1), duration: 200 }),
          ))
        Search({ value: this.searchInput, placeholder: '搜索' })
          .id("searchCaseTitleContentCover")
          .searchButton('搜索', { fontSize: 16 })
          .sharedTransition('SEARCH_ONE_SHOT_DEMO_TRANSITION_ID', { duration: 800, curve: Curve.Linear, delay: 100 })
          .defaultFocus(true)
          .enableKeyboardOnFocus(false)
          .backgroundColor('#E7E9E8')
          .onChange((value) => {
            this.searchInput = value;
          })
          .margin({ left: 10, right: 10 })
          .layoutWeight(1)
          .height(43)
      }
    }
    .hideTitleBar(true)
  }
}

【总结】

组件间切换使用geometryTransition,且必须要必须配合animateTo使用才有动画效果,页面间切换使用共享元素转场 (sharedTransition)

更多关于HarmonyOS 鸿蒙Next中共享元素的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


建议楼主进行组件层级优化试一下,避免过渡效果冲突,Image组件的transition效果可能影响布局稳定性,建议简化过渡动画:

.transition(TransitionEffect.opacity(0.8)
.animation({ duration: 300 })

在跳转后的页面onPageShow生命周期触发布局刷新:

onPageShow() {
  this.updateLayout()
}
  1. 楼主跳转前的搜索如果没有搜索作用的话直接自己封装一个样式一样的组件作为跳转,搜索也才用Search组件试试
  2. 页面的转场效果的话可以使用一镜到底的动画
    一镜到底动效-动画与转场 - 华为HarmonyOS开发者

把Row的宽度设置为100%

鸿蒙Next的共享元素(Shared Element)功能用于实现页面转场时的元素平滑过渡效果。在Ability或Page间跳转时,通过指定共享元素的id和类型(如图片、文本等),系统会自动处理转场动画。开发时需在布局中为共享元素添加transitionName属性,并在startAbility或NavigateTo的parameters中配置共享元素参数(如__sharedElements__)。当前支持的共享元素属性包括位置、大小、透明度等视觉属性的过渡。该功能基于ArkUI框架实现,使用声明式语法配置转场效果。

从您提供的代码和截图来看,这个问题可能与HarmonyOS Next中的共享元素动画(geometryTransition)实现机制有关。以下是可能的原因和解决方案:

  1. 共享元素ID不一致问题:
  • 首页使用的是this.geometryId,而跳转页直接使用了'search'字符串
  • 建议统一使用相同的ID字符串,确保两端匹配
  1. 动画时序问题:
  • 首页使用了animateTo包裹跳转逻辑,而跳转页没有
  • 可以尝试在跳转页也使用animateTo保持动画同步
  1. 布局权重影响:
  • 跳转页Search组件使用了layoutWeight(1),这可能在动画过程中影响尺寸计算
  • 可以尝试移除layoutWeight或调整其值
  1. 硬件加速问题:
  • 这种偶现问题可能与硬件加速渲染有关
  • 可以尝试在Search组件上添加.hardwareAcceleration(true)

建议修改跳转页代码为:

Search({ value: this.searchInput, placeholder: '搜索' })
  .id("searchCaseTitleContentCover")
  .geometryTransition(this.geometryId, {follow: true}) // 使用与首页相同的ID
  .hardwareAcceleration(true)
  // 其他属性保持不变

这种偶现问题通常需要多次测试验证,建议在真机上测试不同场景下的表现。

回到顶部