本文展示了HarmonyOS Next中四种弹窗动画的实现方案:1) 基础缩放动画,通过控制scale和opacity实现渐显效果;2) 底部滑动动画,使用translateY完成视差移动;3) 弹性动画,利用Spring曲线模拟物理弹性;4) 3D翻转动画,通过rotateY实现卡片翻转效果。每种方案都包含完整的代码示例,核心使用animateTo动画API配合状态管理,并详细说明了动画曲线选择、复合属性控制等关键技术点。这些实现方案覆盖了主流UI动画效果,可直接用于实际项目开发。
一、基础弹窗动画实现
// ScalePopup.ets
import { Curve, animateTo } from '@ohos.animation';
@Entry
@Component
struct ScalePopupExample {
@State isShow: boolean = false;
@State scale: number = 0.5;
@State opacity: number = 0;
// 显示弹窗动画
showPopup() {
this.isShow = true;
animateTo({
duration: 300,
curve: Curve.EaseOut
}, () => {
this.scale = 1;
this.opacity = 1;
});
}
// 隐藏弹窗动画
hidePopup() {
animateTo({
duration: 200,
curve: Curve.EaseIn,
onFinish: () => {
this.isShow = false;
}
}, () => {
this.scale = 0.5;
this.opacity = 0;
});
}
build() {
Stack({ alignContent: Alignment.Center }) {
// 主页面内容
Column() {
Button('显示弹窗')
.onClick(() => this.showPopup())
.margin(20)
}
// 弹窗层
if (this.isShow) {
// 半透明背景
Column()
.width('100%')
.height('100%')
.backgroundColor('#000000')
.opacity(0.5 * this.opacity)
.onClick(() => this.hidePopup())
// 弹窗内容
Column() {
Text('HarmonyOS Next')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 10 })
Text('弹窗动画效果展示')
.fontSize(18)
.margin({ bottom: 20 })
Button('关闭')
.onClick(() => this.hidePopup())
.width(120)
.margin(10)
}
.width('80%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(16)
.shadow({ radius: 20, color: '#40000000' })
.scale({ x: this.scale, y: this.scale })
.opacity(this.opacity)
}
}
.width('100%')
.height('100%')
}
}
关键点解析:
-
动画曲线:使用Curve.EaseOut实现平滑加速效果
-
状态管理:@State装饰器控制弹窗状态
-
复合动画:同时控制缩放和透明度
-
层级管理:使用Stack布局实现弹窗覆盖层
二、高级弹窗动画实现
// SlidePopup.ets
import { Curve, animateTo } from '@ohos.animation';
@Entry
@Component
struct SlidePopupExample {
@State isShow: boolean = false;
@State translateY: number = 1000; // 初始位置在屏幕外
showPopup() {
this.isShow = true;
animateTo({
duration: 400,
curve: Curve.EaseOut
}, () => {
this.translateY = 0; // 滑入到屏幕底部
});
}
hidePopup() {
animateTo({
duration: 300,
curve: Curve.EaseIn,
onFinish: () => {
this.isShow = false;
this.translateY = 1000; // 重置位置
}
}, () => {
this.translateY = 1000; // 滑出屏幕
});
}
build() {
Stack({ alignContent: Alignment.Bottom }) {
// 主页面内容...
// 底部弹窗
if (this.isShow) {
// 背景蒙层
Column()
.width('100%')
.height('100%')
.backgroundColor('#000000')
.opacity(0.5)
.onClick(() => this.hidePopup())
// 弹窗内容
Column() {
// 内容区域...
}
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(16, 16, 0, 0)
.shadow({ radius: 10, color: Color.Gray, offsetY: -5 })
.translate({ y: this.translateY })
}
}
}
}
弹性弹窗动画
// SpringPopup.ets
import { Curve, animateTo } from '@ohos.animation';
@Component
struct SpringPopup {
@State scale: number = 0.8;
@State opacity: number = 0;
aboutToAppear() {
// 弹性显示动画
animateTo({
duration: 600,
curve: Curve.Spring({
mass: 1,
stiffness: 400,
damping: 15
})
}, () => {
this.scale = 1;
this.opacity = 1;
});
}
build() {
Column() {
// 弹窗内容...
}
.scale({ x: this.scale, y: this.scale })
.opacity(this.opacity)
}
}
三、3D翻转弹窗动画
// FlipPopup.ets
import { Curve, animateTo } from '@ohos.animation';
@Entry
@Component
struct FlipPopupExample {
@State isShow: boolean = false;
@State angleY: number = 90; // 初始90度(不可见)
@State isFront: boolean = true;
// 3D翻转动画
flipPopup() {
const targetAngle = this.isFront ? 270 : 90;
animateTo({
duration: 800,
curve: Curve.EaseInOut,
onFinish: () => {
this.isFront = !this.isFront;
}
}, () => {
this.angleY = targetAngle;
});
}
build() {
Stack() {
// 主页面内容...
if (this.isShow) {
// 3D容器
Stack({ alignContent: Alignment.Center }) {
// 正面
Column() {
// 正面内容...
}
.rotate({ y: this.angleY })
.opacity(this.isFront ? 1 : 0)
// 背面
Column() {
// 背面内容...
}
.rotate({ y: this.angleY - 180 })
.opacity(this.isFront ? 0 : 1)
}
.perspective(1000)
.onClick(() => this.flipPopup())
}
}
}
}