Ios animations
Skill almasumdev/awesome-ios-agent-skills/.github/skills/ui/ios-animations
Expert guidance on SwiftUI animations — implicit, explicit, matchedGeometryEffect, TimelineView, spring physics, and performance considerations. Use whenever motion is involved.From its SKILL.md
npx -y skills add almasumdev/awesome-ios-agent-skills --skill ios-animationsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.7 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
iOS Animations
Instructions
SwiftUI animations are driven by state changes. The animation describes how a value transitions; your code changes the value.
1. Implicit vs Explicit
Implicit animation — attached to a view, triggered by a specific value:
Circle()
.fill(.blue)
.frame(width: isExpanded ? 120 : 60)
.animation(.spring(response: 0.4, dampingFraction: 0.7), value: isExpanded)
Explicit animation — wrap a state mutation:
Button("Toggle") {
withAnimation(.easeInOut(duration: 0.25)) {
isExpanded.toggle()
}
}
Prefer the value: form of .animation over the value-less variant — it limits what animates.
2. Spring Physics (iOS 17+)
Modern springs are defined in natural terms:
.animation(.spring(duration: 0.45, bounce: 0.3), value: offset)
.animation(.smooth, value: scale) // quick, no overshoot
.animation(.snappy, value: progress) // faster, slight bounce
.animation(.bouncy, value: badgeCount) // playful
3. matchedGeometryEffect
Seamlessly move/resize an element between hierarchies:
struct Gallery: View {
@Namespace private var ns
@State private var selected: Photo?
var body: some View {
ZStack {
grid
if let photo = selected { detail(photo) }
}
}
private var grid: some View {
LazyVGrid(columns: [.init(.adaptive(minimum: 100))]) {
ForEach(photos) { photo in
Image(photo.name)
.resizable()
.matchedGeometryEffect(id: photo.id, in: ns)
.onTapGesture {
withAnimation(.spring) { selected = photo }
}
}
}
}
@ViewBuilder private func detail(_ photo: Photo) -> some View {
Image(photo.name)
.resizable()
.matchedGeometryEffect(id: photo.id, in: ns)
.onTapGesture {
withAnimation(.spring) { selected = nil }
}
}
}
4. Transitions
Control how views enter/leave:
if showBanner {
BannerView()
.transition(.move(edge: .top).combined(with: .opacity))
}
Custom transitions with AnyTransition or Transition protocol (iOS 17+):
struct BlurTransition: Transition {
func body(content: Content, phase: TransitionPhase) -> some View {
content.blur(radius: phase.isIdentity ? 0 : 8).opacity(phase.isIdentity ? 1 : 0)
}
}
5. TimelineView for Continuous Motion
Use when animation is time-based, not state-based (clocks, particle effects, progress rings):
TimelineView(.animation) { timeline in
let t = timeline.date.timeIntervalSinceReferenceDate
Circle()
.fill(.blue)
.scaleEffect(1 + 0.1 * CGFloat(sin(t * 2)))
}
6. Phased Animations (iOS 17+)
Walk a value through discrete phases without imperative timers:
Image(systemName: "heart.fill")
.phaseAnimator([0, 1, 0]) { view, phase in
view.scaleEffect(1 + CGFloat(phase) * 0.4)
} animation: { _ in .spring(duration: 0.35) }
Keyframe animations for multi-property choreography:
.keyframeAnimator(initialValue: Pose()) { view, pose in
view.offset(x: pose.x, y: pose.y).rotationEffect(.degrees(pose.angle))
} keyframes: { _ in
KeyframeTrack(\.x) { LinearKeyframe(100, duration: 0.2); SpringKeyframe(0, duration: 0.4) }
KeyframeTrack(\.angle) { LinearKeyframe(360, duration: 0.6) }
}
7. Performance
- Animate properties, not the whole hierarchy.
opacity,offset,scale,rotationare cheap. - Avoid animating
GeometryReader-measured values — it causes rebuilds. - Respect
accessibilityReduceMotion(see theios-accessibilityskill). - For very large lists, set
.drawingGroup()only when profiling shows it helps — it can hurt otherwise.
8. Reduce Motion
@Environment(\.accessibilityReduceMotion) private var reduceMotion
...
.animation(reduceMotion ? nil : .spring, value: isExpanded)
Checklist
- Animations are scoped with a
value:parameter. - Springs use natural duration/bounce parameters (iOS 17+) where possible.
-
matchedGeometryEffectis used for shared-element transitions instead of manual choreography. - Continuous motion uses
TimelineView, notTimer. -
accessibilityReduceMotiondisables or softens animations. - No animation runs on a property that forces layout on every frame.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.