HarmonyOS 鸿蒙Next中使用 SharedTransition (共享元素转场) 实现图片的无缝缩放跳转
HarmonyOS 鸿蒙Next中使用 SharedTransition (共享元素转场) 实现图片的无缝缩放跳转
如何使用 SharedTransition (共享元素转场) 实现图片的无缝缩放跳转?
// 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实现图片的无缝缩放跳转,核心在于为两个页面的共享元素(如图片)建立关联,并配置转场动画。以下是关键步骤和代码示例:
-
定义共享元素:在源页面和目标页面的对应组件上,使用
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 }) -
配置页面跳转:使用
router.push或router.replace进行导航,系统会自动匹配相同id的共享元素并执行转场动画。router.push({ url: 'pages/DetailPage', params: { imageId: 'imageTransition' } }) -
调整动画参数:在
sharedTransition的配置对象中,可自定义动画时长(duration)、曲线(curve)等属性,以优化缩放效果。
注意事项:
- 共享元素的
id需保持唯一性,避免多个组件冲突。 - 确保两个页面的图片尺寸或布局差异不会导致动画突兀,可通过调整目标页面图片样式平滑过渡。
- 共享元素转场依赖于系统路由栈,需确保页面跳转方式正确。
此方法通过声明式配置简化了复杂动画的实现,无需手动计算位置或尺寸变化,即可实现视觉连贯的图片缩放跳转效果。

