Home > SwiftUI Animations

SwiftUI Animations

SwiftUI์˜ ์„ ์–ธํ˜• ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ์Šคํ…œ์„ ํƒํ—˜ํ•ฉ๋‹ˆ๋‹ค. Spring, Keyframe, Phase ๊ธฐ๋ฐ˜ ์• ๋‹ˆ๋ฉ”์ด์…˜๋ถ€ํ„ฐ geometry ์ „ํ™˜๊นŒ์ง€, ๋ชจ๋˜ iOS ์•ฑ์˜ ๋ชจ์…˜ ๋””์ž์ธ ํ•ต์‹ฌ์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

๊ฐœ์š”

SwiftUI๋Š” ์„ ์–ธํ˜•(Declarative) ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹œ์Šคํ…œ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ(State) ๋ณ€๊ฒฝ์„ ์„ ์–ธํ•˜๋ฉด ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ž๋™์œผ๋กœ ์ค‘๊ฐ„ ํ”„๋ ˆ์ž„์„ ๋ณด๊ฐ„ํ•˜์—ฌ ๋ถ€๋“œ๋Ÿฌ์šด ์ „ํ™˜์„ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. UIKit์˜ ๋ช…๋ นํ˜• ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ๋‹ฌ๋ฆฌ, โ€œ์–ด๋–ป๊ฒŒ ์›€์ง์ผ์ง€โ€๊ฐ€ ์•„๋‹ˆ๋ผ โ€œ์ตœ์ข… ์ƒํƒœ๊ฐ€ ๋ฌด์—‡์ธ์ง€โ€๋งŒ ๊ธฐ์ˆ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์–ธ์ œ ์‚ฌ์šฉํ•˜๋‚˜์š”?

ํ•ต์‹ฌ API

Implicit vs Explicit Animation

Implicit Animation์€ .animation() modifier๋กœ ํŠน์ • ๊ฐ’ ๋ณ€๊ฒฝ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค. Explicit Animation์€ withAnimation ๋ธ”๋ก ์•ˆ์—์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ํ•ด๋‹น ๋ณ€๊ฒฝ์— ์˜ํ–ฅ๋ฐ›๋Š” ๋ชจ๋“  ๋ทฐ๋ฅผ ์• ๋‹ˆ๋ฉ”์ด์…˜ํ•ฉ๋‹ˆ๋‹ค.

// Implicit: ํŠน์ • ํ”„๋กœํผํ‹ฐ์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐ”์ธ๋”ฉ
Circle()
    .scaleEffect(isExpanded ? 1.5 : 1.0)
    .animation(.spring(duration: 0.5), value: isExpanded)

// Explicit: ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ์ ์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ
withAnimation(.spring(duration: 0.5, bounce: 0.3)) {
    isExpanded.toggle()
}

Spring Animation

iOS 17๋ถ€ํ„ฐ spring(duration:bounce:) ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฌผ๋ฆฌ ๊ธฐ๋ฐ˜ ์Šคํ”„๋ง์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. bounce ๊ฐ’์ด 0์ด๋ฉด ์ž„๊ณ„๊ฐ์‡ (critically damped), ์–‘์ˆ˜์ด๋ฉด ๋ฐ”์šด์Šค ํšจ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

KeyframeAnimator

iOS 17์—์„œ ๋„์ž…๋œ KeyframeAnimator๋Š” ์—ฌ๋Ÿฌ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋…๋ฆฝ์ ์ธ ํƒ€์ž„๋ผ์ธ์œผ๋กœ ์ œ์–ดํ•˜๋Š” ํ‚คํ”„๋ ˆ์ž„ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

KeyframeAnimator(initialValue: AnimValues()) { values in
    Circle()
        .scaleEffect(values.scale)
        .rotationEffect(values.rotation)
} keyframes: { _ in
    KeyframeTrack(\.scale) {
        SpringKeyframe(1.5, duration: 0.3)
        SpringKeyframe(1.0, duration: 0.2)
    }
    KeyframeTrack(\.rotation) {
        LinearKeyframe(.degrees(360), duration: 0.5)
    }
}

PhaseAnimator

PhaseAnimator๋Š” ์ •์˜๋œ Phase ๋ฐฐ์—ด์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉฐ ์ž๋™ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ๋‚˜ ๋ฐ˜๋ณต ๋ชจ์…˜์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

matchedGeometryEffect

์„œ๋กœ ๋‹ค๋ฅธ ๋ทฐ ๊ณ„์ธต์— ์žˆ๋Š” ๋‘ ์š”์†Œ ์‚ฌ์ด์˜ ์œ„์น˜/ํฌ๊ธฐ ์ „ํ™˜์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ์ŠคํŠธ์—์„œ ๋””ํ…Œ์ผ ํ™”๋ฉด์œผ๋กœ์˜ Hero Transition ๊ตฌํ˜„์— ํ•ต์‹ฌ์ ์ธ API์ž…๋‹ˆ๋‹ค.

.visualEffect

iOS 17์˜ .visualEffect modifier๋Š” geometry proxy ์ •๋ณด(์œ„์น˜, ํฌ๊ธฐ)์— ๊ธฐ๋ฐ˜ํ•œ ์‹œ๊ฐ ํšจ๊ณผ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค๋‹ˆ๋‹ค. ์Šคํฌ๋กค ์œ„์น˜์— ๋”ฐ๋ฅธ ํŒจ๋Ÿด๋ž™์Šค, ํšŒ์ „, ์Šค์ผ€์ผ ํšจ๊ณผ ๋“ฑ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฐ๋ชจ ๋ชฉ๋ก

์•ฑ์—์„œ๋Š” ๋‘ ๊ฐœ์˜ ์„น์…˜์œผ๋กœ ๊ตฌ๋ถ„๋ฉ๋‹ˆ๋‹ค.

Foundations

๊ฐ’ ๋ณ€ํ™”๋ฅผ ๋ณด๊ฐ„ํ•˜๋Š” ๊ธฐ๋ณธ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํŒจํ„ด.

# ๋ฐ๋ชจ ์„ค๋ช…
1 Spring Playground Spring ํŒŒ๋ผ๋ฏธํ„ฐ(response, dampingFraction, blendDuration)๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์กฐ์ ˆํ•˜๋ฉฐ ์Šคํ”„๋ง ๊ณก์„ ์˜ ๋ณ€ํ™”๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. Bouncy/Smooth/Snappy ํ”„๋ฆฌ์…‹๋„ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
2 Morphing Shapes ์ปค์Šคํ…€ Shape์˜ animatableData: Double์„ ํ™œ์šฉํ•˜์—ฌ circleโ†”star, squareโ†”triangle, heartโ†”diamond ๋ชจํ•‘ ์ „ํ™˜์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์Šฌ๋ผ์ด๋”๋กœ progress๋ฅผ ์ง์ ‘ ์กฐ์ž‘ํ•ด ๋ณด๊ฐ„ ์›๋ฆฌ๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

iOS 17 Multi-State APIs

์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ๋‹ค๋ฃจ๋Š” iOS 17์˜ ์ƒˆ ์• ๋‹ˆ๋ฉ”์ด์…˜ API.

# ๋ฐ๋ชจ ์„ค๋ช…
3 Keyframe Animations KeyframeAnimator๋กœ ์—ฌ๋Ÿฌ ํ”„๋กœํผํ‹ฐ(scale, rotation, offset)๋ฅผ ๋…๋ฆฝ์  ํƒ€์ž„๋ผ์ธ์œผ๋กœ ์กฐํ•ฉํ•˜๋Š” ๋ณตํ•ฉ ์• ๋‹ˆ๋ฉ”์ด์…˜. bounce, orbit, shake, wave ํ”„๋ฆฌ์…‹์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
4 Phase Animations PhaseAnimator๋ฅผ ํ™œ์šฉํ•œ ์ž๋™ ๋ฐ˜๋ณต ์• ๋‹ˆ๋ฉ”์ด์…˜. ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ, ํŽ„์‹ฑ ์•Œ๋ฆผ ๋ฑƒ์ง€, ์ƒํƒœ ์ „ํ™˜ ํ‘œ์‹œ(connecting โ†’ connected โ†’ synced) ์„ธ ๊ฐ€์ง€ ์‚ฌ์šฉ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

์‹ค์ „ ํŒ

Best Practices

์ฃผ์˜ ์‚ฌํ•ญ