swiftui-animation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSwiftUI Animation Expert
SwiftUI 动画专家
Expert guidance for implementing advanced SwiftUI animations and Metal shader integration. Covers animation curves, springs, transitions, matched geometry effects, PhaseAnimator, KeyframeAnimator, and GPU-accelerated shader effects.
为实现高级SwiftUI动画和Metal着色器集成提供专业指导。涵盖动画曲线、弹簧效果、转场、匹配几何效果、PhaseAnimator、KeyframeAnimator以及GPU加速着色器效果。
When to Use This Skill
何时使用该Skill
- Understanding motion design principles and when to use animation
- Making animations accessible and platform-appropriate
- Implementing animations in SwiftUI (springs, easing, keyframes)
- Creating view transitions (fade, slide, scale, custom)
- Building hero animations with matchedGeometryEffect
- Adding GPU-accelerated effects with Metal shaders
- Optimizing animation performance
- Creating multi-phase orchestrated animations
- 理解动效设计原则以及何时使用动画
- 制作可访问且符合平台规范的动画
- 在SwiftUI中实现动画(弹簧、缓动、关键帧)
- 创建视图转场(淡入淡出、滑动、缩放、自定义)
- 使用matchedGeometryEffect构建Hero动画
- 通过Metal着色器添加GPU加速效果
- 优化动画性能
- 创建多阶段编排动画
Quick Reference
快速参考
Animation Basics
动画基础
swift
// Explicit animation (preferred)
withAnimation(.spring(response: 0.4, dampingFraction: 0.75)) {
isExpanded.toggle()
}
// iOS 17+ spring presets
withAnimation(.snappy) { ... } // Fast, small bounce
withAnimation(.smooth) { ... } // Gentle, no bounce
withAnimation(.bouncy) { ... } // More bounceswift
// Explicit animation (preferred)
withAnimation(.spring(response: 0.4, dampingFraction: 0.75)) {
isExpanded.toggle()
}
// iOS 17+ spring presets
withAnimation(.snappy) { ... } // Fast, small bounce
withAnimation(.smooth) { ... } // Gentle, no bounce
withAnimation(.bouncy) { ... } // More bounceCommon Transitions
常见转场
swift
// Basic
.transition(.opacity)
.transition(.scale)
.transition(.slide)
.transition(.move(edge: .bottom))
// Combined
.transition(.move(edge: .trailing).combined(with: .opacity))
// Asymmetric
.transition(.asymmetric(
insertion: .move(edge: .bottom),
removal: .opacity
))swift
// Basic
.transition(.opacity)
.transition(.scale)
.transition(.slide)
.transition(.move(edge: .bottom))
// Combined
.transition(.move(edge: .trailing).combined(with: .opacity))
// Asymmetric
.transition(.asymmetric(
insertion: .move(edge: .bottom),
removal: .opacity
))Matched Geometry Effect
匹配几何效果
swift
@Namespace var namespace
// Source view
ThumbnailView()
.matchedGeometryEffect(id: "hero", in: namespace)
// Destination view
DetailView()
.matchedGeometryEffect(id: "hero", in: namespace)swift
@Namespace var namespace
// Source view
ThumbnailView()
.matchedGeometryEffect(id: "hero", in: namespace)
// Destination view
DetailView()
.matchedGeometryEffect(id: "hero", in: namespace)Metal Shader Effects (iOS 17+)
Metal着色器效果(iOS 17+)
swift
// Color manipulation
.colorEffect(ShaderLibrary.invert())
// Pixel displacement
.distortionEffect(
ShaderLibrary.wave(.float(time)),
maxSampleOffset: CGSize(width: 20, height: 20)
)
// Full layer access
.layerEffect(ShaderLibrary.blur(.float(radius)), maxSampleOffset: .zero)swift
// Color manipulation
.colorEffect(ShaderLibrary.invert())
// Pixel displacement
.distortionEffect(
ShaderLibrary.wave(.float(time)),
maxSampleOffset: CGSize(width: 20, height: 20)
)
// Full layer access
.layerEffect(ShaderLibrary.blur(.float(radius)), maxSampleOffset: .zero)Reference Materials
参考资料
Detailed documentation is available in :
references/-
motion-guidelines.md - HIG Motion design principles
- Purpose-driven motion philosophy
- Accessibility requirements
- Platform-specific considerations (iOS, visionOS, watchOS)
- Animation anti-patterns to avoid
-
animations.md - Complete animation API guide
- Implicit vs explicit animations
- Spring parameters and presets
- Animation modifiers (speed, delay, repeat)
- PhaseAnimator for multi-step sequences
- KeyframeAnimator for property-specific timelines
- Custom animatable properties
-
transitions.md - View transition guide
- Built-in transitions (opacity, scale, slide, move)
- Combined and asymmetric transitions
- Matched geometry effect implementation
- Hero animation patterns
- Content transitions (iOS 17+)
- Custom transition creation
-
metal-shaders.md - GPU shader integration
- SwiftUI shader modifiers (colorEffect, distortionEffect, layerEffect)
- Writing Metal shader functions
- Embedding MTKView with UIViewRepresentable
- Cross-platform Metal integration (iOS/macOS)
- Performance considerations
详细文档可在目录中获取:
references/-
motion-guidelines.md - HIG动效设计原则
- 目标导向的动效理念
- 可访问性要求
- 平台特定考量(iOS、visionOS、watchOS)
- 需要避免的动画反模式
-
animations.md - 完整动画API指南
- 隐式与显式动画
- 弹簧参数与预设
- 动画修饰符(速度、延迟、重复)
- 用于多步骤序列的PhaseAnimator
- 用于属性特定时间线的KeyframeAnimator
- 自定义可动画属性
-
transitions.md - 视图转场指南
- 内置转场(淡入淡出、缩放、滑动、移动)
- 组合与非对称转场
- 匹配几何效果实现
- Hero动画模式
- 内容转场(iOS 17+)
- 自定义转场创建
-
metal-shaders.md - GPU着色器集成
- SwiftUI着色器修饰符(colorEffect、distortionEffect、layerEffect)
- 编写Metal着色器函数
- 使用UIViewRepresentable嵌入MTKView
- 跨平台Metal集成(iOS/macOS)
- 性能考量
Common Patterns
常见模式
Expandable Card
可展开卡片
swift
struct ExpandableCard: View {
@State private var isExpanded = false
var body: some View {
VStack {
RoundedRectangle(cornerRadius: isExpanded ? 20 : 12)
.fill(.blue)
.frame(
width: isExpanded ? 300 : 150,
height: isExpanded ? 400 : 100
)
}
.onTapGesture {
withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
isExpanded.toggle()
}
}
}
}swift
struct ExpandableCard: View {
@State private var isExpanded = false
var body: some View {
VStack {
RoundedRectangle(cornerRadius: isExpanded ? 20 : 12)
.fill(.blue)
.frame(
width: isExpanded ? 300 : 150,
height: isExpanded ? 400 : 100
)
}
.onTapGesture {
withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
isExpanded.toggle()
}
}
}
}List Item Appearance
列表项出现效果
swift
ForEach(Array(items.enumerated()), id: \.element.id) { index, item in
ItemRow(item: item)
.transition(.asymmetric(
insertion: .move(edge: .trailing).combined(with: .opacity),
removal: .move(edge: .leading).combined(with: .opacity)
))
.animation(.spring().delay(Double(index) * 0.05), value: items)
}swift
ForEach(Array(items.enumerated()), id: \.element.id) { index, item in
ItemRow(item: item)
.transition(.asymmetric(
insertion: .move(edge: .trailing).combined(with: .opacity),
removal: .move(edge: .leading).combined(with: .opacity)
))
.animation(.spring().delay(Double(index) * 0.05), value: items)
}Pulsing Indicator
脉冲指示器
swift
Circle()
.fill(.blue)
.frame(width: 20, height: 20)
.scaleEffect(isPulsing ? 1.2 : 1.0)
.opacity(isPulsing ? 0.6 : 1.0)
.onAppear {
withAnimation(.easeInOut(duration: 1.0).repeatForever(autoreverses: true)) {
isPulsing = true
}
}swift
Circle()
.fill(.blue)
.frame(width: 20, height: 20)
.scaleEffect(isPulsing ? 1.2 : 1.0)
.opacity(isPulsing ? 0.6 : 1.0)
.onAppear {
withAnimation(.easeInOut(duration: 1.0).repeatForever(autoreverses: true)) {
isPulsing = true
}
}Best Practices
最佳实践
- Motion should be purposeful - Don't add animation for its own sake; support the experience without overshadowing it
- Make motion optional - Supplement with haptics and audio; never use motion as the only way to communicate
- Aim for brevity - Brief, precise animations feel lightweight and convey information effectively
- Prefer explicit animations - Use over
withAnimationmodifier for clarity.animation() - Use spring animations - They feel more natural and iOS-native
- Start with - Good default for most interactions
.spring(response: 0.35, dampingFraction: 0.8) - Keep animations under 400ms - Longer feels sluggish
- Let people cancel motion - Don't force users to wait for animations to complete
- Test on device - Simulator animation timing differs
- Profile shader performance - GPU time matters for complex effects
- 动效应具备目的性 - 不要为了动画而添加动画;应辅助体验而非喧宾夺主
- 让动效可选项 - 配合触觉反馈和音频;永远不要将动效作为唯一的信息传递方式
- 力求简洁 - 简短、精准的动画感觉轻盈且能有效传达信息
- 优先使用显式动画 - 为了清晰性,优先使用而非
withAnimation修饰符.animation() - 使用弹簧动画 - 它们感觉更自然,更符合iOS原生风格
- 从开始 - 这是大多数交互的良好默认值
.spring(response: 0.35, dampingFraction: 0.8) - 保持动画时长在400ms以内 - 更长的动画会让人感觉迟缓
- 允许用户取消动效 - 不要强迫用户等待动画完成
- 在设备上测试 - 模拟器的动画计时与实际设备不同
- 剖析着色器性能 - 对于复杂效果,GPU耗时至关重要
Troubleshooting
故障排除
Animation not working
动画不生效
- Ensure state change is wrapped in
withAnimation - Check that the property is animatable
- Verify the view is actually changing
- 确保状态变化被包裹在中
withAnimation - 检查属性是否支持动画
- 验证视图是否真的发生了变化
Matched geometry jumps
匹配几何效果出现跳跃
- Both views must use the same ID and namespace
- Use explicit when toggling
withAnimation - Check for proper layering
zIndex
- 两个视图必须使用相同的ID和命名空间
- 切换时使用显式的
withAnimation - 检查以确保正确的层级
zIndex
Shader not appearing
着色器不显示
- Verify file is added to target
.metal - Check shader function signature matches expected format
- Ensure is set correctly for distortion effects
maxSampleOffset
- 确认文件已添加到目标中
.metal - 检查着色器函数签名是否与预期格式匹配
- 确保为扭曲效果正确设置了
maxSampleOffset