Ios animations
Skill almasumdev/awesome-ios-agent-skills/.github/skills/ui/ios-animations
Curated agent skills, conventions, and workflows for building iOS apps (Swift, SwiftUI, UIKit) with AI coding agents.
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.
What its author says it does
Copied from the file, not written here
Expert guidance on SwiftUI animations — implicit, explicit, matchedGeometryEffect, TimelineView, spring physics, and performance considerations. Use whenever motion is involved.
SKILL.md
4.7 KB, 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.