学习目标
- 理解SwiftUI中动画的基本概念和工作原理
- 掌握使用
.animation()修饰符创建隐式动画 - 掌握使用
withAnimation函数创建显式动画 - 学习使用
transition创建视图过渡效果 - 了解组合动画和自定义动画曲线
学习内容
1. SwiftUI动画基础
SwiftUI中的动画是通过声明式的方式实现的。当视图的状态发生变化时,SwiftUI会自动计算中间状态并平滑过渡。
2. 隐式动画
使用.animation()修饰符可以创建隐式动画。当修饰符绑定的值发生变化时,视图会自动产生动画效果。
2.1 基本用法
struct ImplicitAnimationView: View {
@State private var scale: CGFloat = 1.0
var body: some View {
Button("Tap Me") {
scale += 0.5
}
.scaleEffect(scale)
.animation(.default, value: scale) // 当scale变化时应用动画
}
}
2.2 动画类型
SwiftUI提供了多种预定义的动画曲线:
.default- 默认动画.easeIn- 开始慢,然后加速.easeOut- 开始快,然后减速.easeInOut- 开始和结束慢,中间快.linear- 匀速.spring()- 弹簧效果
3. 显式动画
使用withAnimation函数可以创建显式动画,它允许你精确控制哪些状态变化应该产生动画。
struct ExplicitAnimationView: View {
@State private var angle: Double = 0
@State private var isRotating = false
var body: some View {
VStack {
Button("Rotate") {
withAnimation(.easeInOut(duration: 1)) {
angle += 45
isRotating.toggle()
}
}
Rectangle()
.frame(width: 100, height: 100)
.foregroundColor(isRotating ? .red : .blue)
.rotationEffect(.degrees(angle))
}
}
}
4. 视图过渡
transition修饰符用于控制视图出现和消失时的动画效果。
4.1 基本过渡
struct TransitionView: View {
@State private var show = false
var body: some View {
VStack {
Button("Toggle") {
withAnimation {
show.toggle()
}
}
if show {
Text("Hello, SwiftUI!")
.transition(.slide) // 滑入滑出效果
}
}
}
}
4.2 组合过渡
可以组合多个过渡效果:
.transition(.opacity.combined(with: .scale))
4.3 非对称过渡
可以为插入和移除设置不同的过渡:
.transition(.asymmetric(
insertion: .move(edge: .leading),
removal: .move(edge: .trailing)
))
5. 高级动画
5.1 自定义动画曲线
.animation(
Animation.timingCurve(0.2, 0.8, 0.4, 1.0, duration: 1),
value: scale
)
5.2 动画延迟和重复
.animation(
Animation.easeInOut(duration: 1)
.delay(0.5)
.repeatCount(3, autoreverses: true),
value: scale
)
5.3 匹配几何效果
使用matchedGeometryEffect可以在不同视图之间创建平滑的几何变换动画:
struct MatchedGeometryView: View {
@Namespace private var animation
@State private var isExpanded = false
var body: some View {
VStack {
if isExpanded {
Rectangle()
.matchedGeometryEffect(id: "shape", in: animation)
.frame(width: 200, height: 200)
.foregroundColor(.blue)
} else {
Circle()
.matchedGeometryEffect(id: "shape", in: animation)
.frame(width: 100, height: 100)
.foregroundColor(.red)
}
Button("Toggle") {
withAnimation {
isExpanded.toggle()
}
}
}
}
}
实践练习
- 创建按钮动画:
- 创建一个按钮,点击时放大并改变颜色,使用隐式动画实现。
- 修改动画类型,比较
.easeIn、.easeOut、.easeInOut和.spring()的区别。
- 构建进度条:
- 创建一个可调整的进度条视图,使用显式动画平滑过渡进度变化。
- 添加一个重置按钮,点击时进度条平滑回到起点。
- 实现卡片翻转:
- 创建一个卡片视图,正面显示图片,背面显示文字。
- 使用3D旋转动画实现卡片翻转效果。
- 构建自定义过渡:
- 创建一个视图切换效果,新视图从底部滑入,旧视图向上淡出。
- 使用
.asymmetric过渡实现。
思考题
- 隐式动画和显式动画的主要区别是什么?在什么情况下应该选择哪种方式?
- 如何优化复杂视图的动画性能?
matchedGeometryEffect解决了什么问题?在什么场景下特别有用?
975

被折叠的 条评论
为什么被折叠?



