ArkUI animation:状态一变,页面别硬跳
【摘要】 今天我们要用 animation 做一个最常见的动效:状态改变以后,卡片不要突然跳到另一个样子,而是顺着尺寸、颜色、透明度、缩放和位移慢慢变过去。 准备 这一页只需要一个 ArkTS 页面:entry/src/main/ets/pages/arkUI/motion/ArkUIAnimationDemo.ets。 我们不
ArkUI animation:状态一变,页面别硬跳
今天我们要用 animation 做一个最常见的动效:状态改变以后,卡片不要突然跳到另一个样子,而是顺着尺寸、颜色、透明度、缩放和位移慢慢变过去。
准备
这一页只需要一个 ArkTS 页面:entry/src/main/ets/pages/arkUI/motion/ArkUIAnimationDemo.ets。
我们不引入业务数据,也不讲状态管理原理。这里的 @State 只负责触发动画。
第一步:先准备两个状态
@State expanded: boolean = false;
@State highlighted: boolean = false;
expanded 控制卡片是收起还是展开,highlighted 控制提醒卡片是不是强调态。状态本身很普通,真正让页面动起来的是后面的 .animation(...)。
第二步:把 animation 放在会变化的属性后面
.width(this.expanded ? '100%' : '76%')
.height(this.expanded ? 156 : 96)
.backgroundColor(this.expanded ? '#2563EB' : '#FFFFFF')
.opacity(this.expanded ? 1 : 0.86)
.scale({ x: this.expanded ? 1 : 0.96, y: this.expanded ? 1 : 0.96 })
.translate({ x: this.expanded ? 0 : 18, y: this.expanded ? 0 : 8 })
.animation({ duration: 420, curve: Curve.EaseInOut })
这一步很简单:哪些属性会跟着状态变,就把它们写清楚。animation 会在状态变化时接住这些属性,不让它们硬切。
容易踩坑的地方是别把所有动效都塞进一页。这里我们只看属性动画,组件插入移除交给下一篇 transition。
运行后看什么
打开案例页后,点“展开卡片”。你应该能看到卡片宽高、颜色、透明度、缩放和位移一起过渡。再点下面那张提醒卡片,它会在普通态和强调态之间切换。
你平时写页面时,最容易突然跳变的是哪类 UI?是卡片展开、按钮状态,还是列表项选中?可以带着这个问题继续改这页参数。
完整示例代码
@Entry
@Component
struct ArkUIAnimationDemo {
@State expanded: boolean = false;
@State highlighted: boolean = false;
@Builder
sectionTitle(title: string, desc: string) {
Column({ space: 6 }) {
Text(title)
.fontSize(19)
.fontWeight(FontWeight.Bold)
.fontColor('#111827')
Text(desc)
.fontSize(13)
.fontColor('#6B7280')
.lineHeight(20)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
build() {
Scroll() {
Column({ space: 22 }) {
Column({ space: 8 }) {
Text('ArkUI animation')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#111827')
Text('状态一变,页面别硬跳')
.fontSize(16)
.fontColor('#4B5563')
Text('这一页只看属性动画:状态改了以后,尺寸、颜色、透明度、缩放和位移跟着补一段过渡。')
.fontSize(14)
.fontColor('#6B7280')
.lineHeight(22)
}
.width('100%')
.alignItems(HorizontalAlign.Start)
this.sectionTitle('一段 animation 管一组属性', 'animation 会跟随状态变化工作,适合卡片展开、按钮强调、模块轻微移动这类场景。')
Column({ space: 16 }) {
Column({ space: 10 }) {
Text(this.expanded ? '展开后的卡片' : '收起的卡片')
.fontSize(this.expanded ? 21 : 17)
.fontWeight(FontWeight.Bold)
.fontColor(this.expanded ? '#FFFFFF' : '#1D4ED8')
Text(this.expanded ? '尺寸、背景色、透明度和位移一起变化,用户能看清页面发生了什么。' : '点下面按钮,让这张卡片自然展开。')
.fontSize(13)
.fontColor(this.expanded ? '#DBEAFE' : '#475569')
.lineHeight(20)
}
.width(this.expanded ? '100%' : '76%')
.height(this.expanded ? 156 : 96)
.padding(18)
.borderRadius(this.expanded ? 22 : 14)
.backgroundColor(this.expanded ? '#2563EB' : '#FFFFFF')
.opacity(this.expanded ? 1 : 0.86)
.scale({ x: this.expanded ? 1 : 0.96, y: this.expanded ? 1 : 0.96 })
.translate({ x: this.expanded ? 0 : 18, y: this.expanded ? 0 : 8 })
.shadow({
radius: this.expanded ? 18 : 6,
color: this.expanded ? '#402563EB' : '#1A000000',
offsetX: 0,
offsetY: this.expanded ? 10 : 4
})
.animation({ duration: 420, curve: Curve.EaseInOut })
.alignItems(HorizontalAlign.Start)
Button(this.expanded ? '收起卡片' : '展开卡片')
.height(40)
.fontSize(14)
.fontColor('#FFFFFF')
.backgroundColor('#111827')
.borderRadius(20)
.padding({ left: 18, right: 18 })
.onClick(() => {
this.expanded = !this.expanded;
})
}
.width('100%')
.padding(16)
.borderRadius(16)
.backgroundColor('#F8FAFC')
.border({ width: 1, color: '#E5E7EB' })
.alignItems(HorizontalAlign.Start)
this.sectionTitle('强调也可以有过渡', '颜色、透明度和缩放不一定要跳变。轻一点,页面会稳很多。')
Row({ space: 12 }) {
Column({ space: 6 }) {
Text('消息提醒')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(this.highlighted ? '#FFFFFF' : '#0F766E')
Text(this.highlighted ? '当前被强调' : '普通展示状态')
.fontSize(13)
.fontColor(this.highlighted ? '#CCFBF1' : '#64748B')
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
Text(this.highlighted ? 'ON' : 'OFF')
.fontSize(13)
.fontWeight(FontWeight.Bold)
.fontColor(this.highlighted ? '#0F766E' : '#64748B')
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.borderRadius(12)
.backgroundColor(this.highlighted ? '#CCFBF1' : '#E2E8F0')
}
.width('100%')
.padding(18)
.borderRadius(16)
.backgroundColor(this.highlighted ? '#0F766E' : '#FFFFFF')
.scale({ x: this.highlighted ? 1.02 : 1, y: this.highlighted ? 1.02 : 1 })
.opacity(this.highlighted ? 1 : 0.88)
.animation({ duration: 320, curve: Curve.EaseOut })
.onClick(() => {
this.highlighted = !this.highlighted;
})
}
.width('100%')
.padding(24)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
}
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)