HarmonyOS 鸿蒙Next中使用 SharedTransition (共享元素转场) 实现图片的无缝缩放跳转

HarmonyOS 鸿蒙Next中使用 SharedTransition (共享元素转场) 实现图片的无缝缩放跳转

如何使用 SharedTransition (共享元素转场) 实现图片的无缝缩放跳转?

4 回复
// xxx.ets
@Entry
@Component
struct SharedTransitionExample {
  build() {
    Column() {
      // $r('app.media.ic_health_heart')需要替换为开发者所需的图像资源文件。
      Image($r('app.media.ic_health_heart')).width(50).height(50).margin({ left: 20, top: 20 })
      .sharedTransition('sharedImage', { duration: 800, curve: Curve.Linear, delay: 100 })
    }.width('100%').height('100%').alignItems(HorizontalAlign.Start)
    .onClick(() => {
      this.getUIContext().getRouter().pushUrl({ url: 'pages/PageB' })
    })
  }

  pageTransition() {
    PageTransitionEnter({ type: RouteType.None, duration: 0 })
    PageTransitionExit({ type: RouteType.None, duration: 0 })
  }
}
// PageB.ets
@Entry
@Component
struct PageBExample {
  build() {
    Stack() {
      // $r('app.media.ic_health_heart')需要替换为开发者所需的图像资源文件。
      Image($r('app.media.ic_health_heart')).width(150).height(150)
      .sharedTransition('sharedImage', { duration: 800, curve: Curve.Linear, delay: 100 })
    }.width('100%').height('100%')
  }

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

更多关于HarmonyOS 鸿蒙Next中使用 SharedTransition (共享元素转场) 实现图片的无缝缩放跳转的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


实现思路

首先配置路由跳转模式,使用 router.pushUrl 时,设置 RouterMode.Single。

其次定义共享 ID,在列表页(源页面)和详情页(目标页面)的 Image 组件上,使用 sharedTransition 属性。需要注意:两个组件设置完全相同的字符串 id。

最后我们在设置转场参数,配置 duration(动画时长)、curve(动画曲线),调整 zIndex,确保跳转过程中图片浮在其他内容之上。

效果

完整代码

import router from '@ohos.router';

// 定义数据模型
class ImageModel {
  id: string;
  url: string;
  title: string;

  constructor(id: string, url: string, title: string) {
    this.id = id;
    this.url = url;
    this.title = title;
  }
}

@Entry
@Component
struct Index {
  private dataList: ImageModel[] = [
    new ImageModel('1', 'https://www.daymw.com/wp-content/themes/yusi/img/pic/5.jpg', '风景图片 1'),
    new ImageModel('2', 'https://www.daymw.com/wp-content/themes/yusi/img/pic/3.jpg', '城市建筑 2'),
    new ImageModel('3', 'https://www.daymw.com/wp-content/themes/yusi/img/pic/4.jpg', '自然风光 3'),
    new ImageModel('4', 'https://www.daymw.com/wp-content/themes/yusi/img/pic/1.jpg', '抽象艺术 4'),
  ];

  build() {
    Column() {
      Text("共享元素转场演示")
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 40, bottom: 20 })

      List({ space: 15 }) {
        ForEach(this.dataList, (item: ImageModel) => {
          ListItem() {
            Row() {
              Image(item.url)
                .width(80)
                .height(80)
                .borderRadius(8)
                .objectFit(ImageFit.Cover)
                .sharedTransition('shared_image_id_' + item.id, {
                  duration: 400,
                  curve: Curve.FastOutSlowIn
                })
                .onClick(() => {
                  this.jumpToDetail(item);
                })

              Text(item.title)
                .fontSize(18)
                .margin({ left: 15 })
                .layoutWeight(1)
            }
            .width('100%')
            .padding(15)
            .backgroundColor('#FFFFFF')
            .borderRadius(12)
            .shadow({ radius: 5, color: '#1A000000', offsetY: 2 })
          }
        })
      }
      .layoutWeight(1)
      .width('90%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F3F5')
  }

  // 跳转详情页
  private jumpToDetail(item: ImageModel) {
    router.pushUrl({
      url: 'pages/Detail',
      params: {
        id: item.id,
        url: item.url,
        title: item.title
      }
    }, router.RouterMode.Single);
  }
}
import router from '@ohos.router';

@Entry
@Component
struct Detail {
  @State imgUrl: string = '';
  @State imgId: string = '';
  @State imgTitle: string = '';

  aboutToAppear(): void {
    const params = router.getParams() as Record<string, Object>;
    if (params) {
      this.imgId = params['id'] as string;
      this.imgUrl = params['url'] as string;
      this.imgTitle = params['title'] as string;
    }
  }

  build() {
    Column() {
      Row() {
        Image($r('sys.symbol.chevron_left'))
          .width(24)
          .height(24)
          .fillColor(Color.Black)
          .onClick(() => {
            router.back();
          })

        Text(this.imgTitle)
          .fontSize(20)
          .fontWeight(FontWeight.Medium)
          .layoutWeight(1)
          .textAlign(TextAlign.Center)
      }
      .width('100%')
      .height(56)
      .padding({ left: 15, right: 15 })

      
      Scroll() {
        Column() {
          Image(this.imgUrl)
            .width('100%')
            .height(300) 
            .borderRadius({ topLeft: 0, topRight: 0, bottomLeft: 16, bottomRight: 16 })
            .objectFit(ImageFit.Cover)
              // 关键:ID 必须与源页面完全一致!
            .sharedTransition('shared_image_id_' + this.imgId, {
              duration: 400,
              curve: Curve.FastOutSlowIn
            })

          Text("这里是详情内容...")
            .fontSize(16)
            .margin(20)
            .width('100%')

          // 模拟长内容
          ForEach(Array.from({ length: 20 }, (_:number, i:number) => i), (item: number) => {
            Text(`模拟文本行 ${item}`)
              .fontSize(14)
              .fontColor('#666666')
              .width('100%')
              .margin({ bottom: 10 })
          })
        }
        .width('100%')
      }
      .layoutWeight(1)
      .backgroundColor('#FFFFFF')
    }
    .width('100%')
    .height('100%')
  }
}

在HarmonyOS Next中,SharedTransition组件用于实现共享元素转场效果,可实现图片在不同页面间的无缝缩放跳转。开发者需在源页面和目标页面为共享元素设置相同的sharedTransitionName属性,并配置动画参数。通过Navigation或路由跳转时,系统会自动识别同名元素并执行平滑过渡动画,支持缩放、位移等视觉效果。该功能基于ArkUI框架实现,无需依赖Java或C语言。

在HarmonyOS Next中,使用SharedTransition实现图片的无缝缩放跳转,核心在于为两个页面的共享元素(如图片)建立关联,并配置转场动画。以下是关键步骤和代码示例:

  1. 定义共享元素:在源页面和目标页面的对应组件上,使用sharedTransition修饰符并设置相同的id

    // 源页面 Image 组件
    Image($r('app.media.image'))
      .sharedTransition('imageTransition', { duration: 300, curve: Curve.Linear })
    
    // 目标页面 Image 组件
    Image($r('app.media.image'))
      .sharedTransition('imageTransition', { duration: 300, curve: Curve.Linear })
    
  2. 配置页面跳转:使用router.pushrouter.replace进行导航,系统会自动匹配相同id的共享元素并执行转场动画。

    router.push({
      url: 'pages/DetailPage',
      params: { imageId: 'imageTransition' }
    })
    
  3. 调整动画参数:在sharedTransition的配置对象中,可自定义动画时长(duration)、曲线(curve)等属性,以优化缩放效果。

注意事项:

  • 共享元素的id需保持唯一性,避免多个组件冲突。
  • 确保两个页面的图片尺寸或布局差异不会导致动画突兀,可通过调整目标页面图片样式平滑过渡。
  • 共享元素转场依赖于系统路由栈,需确保页面跳转方式正确。

此方法通过声明式配置简化了复杂动画的实现,无需手动计算位置或尺寸变化,即可实现视觉连贯的图片缩放跳转效果。

回到顶部