[SwiftUI] Animating Views and Transitions
์๋ฌธ: ํํ ๋ฆฌ์ผ ํ์ด์ง
Animating Views and Transitions
์ฝ๋๋ก ๋ง๋ค์ด๋ณด๋ ์ ๋๋ฉ์ด์ ! storyboard๋ก ๋ง๋ค ๋๋ view๋ฅผ ์ ๋๋ฉ์ด์ ํ ์ผ์ด ๋ง์ด ์์ด์ ๊ฐ๋จํ ์ ๋๋ฉ์ด์ ๋ง ์ถ๊ฐํด๋ดค์๋ค.
์ฌ๊ธฐ์๋ ์ด๋ค Animation๊ณผ Transition์ ์ฌ์ฉํ ๊น?
Add Hiking Data to the App
- animation์ ์ถ๊ฐํ๊ธฐ ์ ์ animation์ ์ ์ฉํ ๋ฐ์ดํฐ๋ฅผ ๋จผ์ ์ถ๊ฐํด์ค๋ค.
ํํ ๋ฆฌ์ผ ํ์ด์ง์ ํ๋ก์ ํธ๋ฅผ ๋ค์ด๋ฐ์ Resource ํด๋์ ์๋ hikeData.json ํ์ผ์ ์ฎ๊ฒจ์ค๋ค.
json ํ์ผ ์์ ์ฌ๋ฌ ๊ฐ๋ค์ด ๋ค์ด์๋ค. (name, id, distance, difficulty ๋ฑ๋ฑ)
- json ๋ฐ์ดํฐ๋ฅผ ํ์ฑํ Hike.swift ํ์ผ์ ์์ฑํ๋ค.
Landmark ์ฒ๋ผ Codable์ ์ฑํํ ๊ฑด๋ฐ Hike๋ Landmark์ ๋ง์ฐฌ๊ฐ์ง๋ก key ๊ฐ์ด ๋งค์นญ๋์ด์ผ ํ๋ค.
struct Hike: Codable, Hashable, Identifiable {
var id: Int
var name: String
var distance: Double
var difficulty: Int
var observations: [Observation]
static var formatter = LengthFormatter()
var distanceText: String {
Hike.formatter
.string(fromValue: distance, unit: .kilometer)
}
struct Observation: Codable, Hashable {
var distanceFromStart: Double
var elevation: Range<Double>
var pace: Range<Double>
var heartRate: Range<Double>
}
}
observations์ ๋ด๋ถ์ elevation, pace, heartRate๊ฐ ๋ค์ด์๊ธฐ ๋๋ฌธ์ Observation์ ๋ณ๋์ struct๋ก ์์ฑํ๋ค.
- ModelData์์ Hide ๋ฐ์ดํฐ ๋ก๋
landmarks์ ๋ค๋ฅด๊ฒ hide ๋ฐ์ดํฐ๋ ๋ก๋๋ ์ดํ ๊ฐ์ด ๋ณ๊ฒฝ๋ ์ผ์ด ์์ผ๋ฏ๋ก @Published๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค.
- Hike ํด๋ ์ฎ๊ธฐ๊ธฐ
๋ค์ด๋ก๋ ๋ฐ์ ํ๋ก์ ํธ์ Resource ํ์ผ ๋ด๋ถ์ ์๋ Hike ํด๋๋ฅผ ๊ฐ์ ธ์จ๋ค.
Animation์ ๊ตฌํํ๊ธฐ ์ํด ์ ํ์์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ค ๊ทธ๋ํ ์ฝ๋.
HikeView ํ์ผ์ ์ด์ด preview๋ฅผ ์คํ์์ผ๋ณด๋ฉด ๊ทธ๋ํ๊ฐ ์ ๋์ค๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
Add Animations to Individual Views
animation(_:)
, animation(_:value:)
์ฌ์ฉํ๊ธฐ
- Button Rotation
HikeView์์ DetailView๋ฅผ ๋ ธ์ถํ๊ธฐ ์ํด ์ฌ์ฉํ ๋ฒํผ(>)์ ๋๋ ์ ๋ ํ์ ํ๋ ์ ๋๋ฉ์ด์ ์ด ๋ณด์ด๋๋ก ์์ ํ๋ค.
- .animation(.easeInOut, value: showDetail) ์ถ๊ฐํ๋ฉด ์๋์ฒ๋ผ ๋ณ๊ฒฝ๋๋ค.
As Is | To Be |
---|---|
ํ์ ์ด ๋๋ ๊ฒ ๋ณด์ธ๋ค..!!!
.easeInOut ๋์ .spring()์ ์ฌ์ฉํ ์๋ ์๋ค.
- .scaleEffect(showDetail ? 1.5 : 1)๋ฅผ ์ถ๊ฐํ๋ฉด detail ๊ทธ๋ํ๊ฐ ๋์ฌ ๋ ๋ฒํผ์ด ์ปค์ง๋ค. (1.5๋ฐฐ)
Animate the Effects of State Changes
์ฌ๊ธฐ์๋ withAnimation
์ด๋ผ๋ ์น๊ตฌ๋ฅผ ์ฌ์ฉํ๋ค.
์๋ ๊ฒ button์ toggle ๋ฉ์๋๋ฅผ withAnimation์ผ๋ก ๊ฐ์ธ์ฃผ๋ฉด
๊ต์ฅํ detail ๊ทธ๋ํ๊ฐ ์ค๋ฌด์คํ๊ฒ ์ด๋ฆฐ๋ค.
withAnimation์๋ .easyOut ๊ฐ์ ๊ฐ์ ์ฌ์ฉํ ์ ์๋ค. animation์ด ์๋ฃ๋๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ๋ ์ค์ ํ ์ ์๋๋ฐ, ์ ์ฝ๋์ withAnimation์
withAnimation(.easeInOut(duration: 4))
์ผ๋ก ๋ณ๊ฒฝํ๋ฉด ๋๋ค.
Customize View Transitions
transition(_:)
์ฌ์ฉํ๊ธฐ
detail ํ๋ฉด์ ๋ ธ์ถํ ๋ transition์ slide ๊ฐ์ ์ฃผ๋ฉด
๊ต์ฅํ ๋๋ฆฌ๊ฒโฆ ๊ทธ๋ํ๊ฐ ๋ฐ๋ ค๋ค์ด์จ๋ค.
View์ Transition์ ์ปค์คํ ํ ๋ AnyTransition ์ ๊ฐ์ ์ถ๊ฐํ๊ณ ๊ด๋ฆฌํ ์ ์๋ค. ์๋์ ๊ฐ์ด extension์ moveAndFade๋ฅผ ์ถ๊ฐํ๋ฉด
extension AnyTransition {
static var moveAndFade: AnyTransition {
AnyTransition.slide
}
}
๋์ผํ ์ฝ๋๋ฅผ ์ด๋ ๊ฒ ํธ์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ์ง๊ธ์ ๊ฐ๋จํ transition์ด์ง๋ง ํ์ ๋ณต์กํ transition์ ๋ง๋ค์ด ์ฌ๋ฌ ๋ทฐ์์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค. (์์ฃผ ์ข์๋ฐ..?)
Compose Animations for Complex Effects
- canvas ํ๊ณ ์
๋ค๋ฅธ ํ์ผ๋ก ๋์ด๊ฐ์ ๋๋ ํ๋ฆฌ๋ทฐ๋ฅผ ํ์ธํ ์ ์๋๋ก canvas๋ฅผ ๊ณ ์ ํ๋ค. + showDetail์ true๋ก ์ค์ ํ๋ค.
- Animation์ ripple() ์ถ๊ฐ
extension Animation {
static func ripple() -> Animation {
Animation.default
}
}
GraphCapsule์ .animation(.ripple())๊น์ง ์ ์ฉํ๋ฉด ๊ทธ๋ํ์ animation์ด ์ ์ฉ๋๋ค.
- Animation.default ๋์ spring ์ ์ฉ
static func ripple() -> Animation {
Animation.spring(dampingFraction: 0.5)
.speed(2)
}
์๊น ๋ฒํผ์ ์ ์ฉํ ๋ ๋ชฐ๋๋๋ฐ ๊ทธ๋ํ๊ฐ ํ์คํ ํ๋ ๊ฒ ๋ณด์ธ๋ค.
- ์ต์ข ์ ๋๋ฉ์ด์
static func ripple(index: Int) -> Animation {
Animation.spring(dampingFraction: 0.5)
.speed(2)
.delay(0.03 * Double(index))
}
๊ทธ๋ํ์ ๊ฐ index๋ณ๋ก ๋๋ ์ด๋ฅผ ์ฃผ๋๋ก ํ๋ฉด ์์ฑ.
๋ฒ์ธ
- moveAndFade ์ฝ๋ ๋ณ๊ฒฝ
.asymmetric( insertion: .move(edge: .trailing).combined(with: .opacity), removal: .scale.combined(with: .opacity) )
๋ง๋ฌด๋ฆฌ
transition์ด๋ animation์ ๋ง์ง ์ผ์ด ์ ์์๋๋ฐ, ์ด๋ ๊ฒ ์ปค์คํ ๋ ํ๊ณ extension์ผ๋ก ๊ด๋ฆฌ๋ ํ๋๊น ๊ฝค ์ข์๋ณด์ธ๋ค. ๋์ค์ ๋ฐ๋ก ์ฑ ๋ง๋ค ๋ ์ฌ์ฉํด๋ณด๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค. (๋ฌผ๋ก ์ฝ์ง์ ๋ง์ด ํ๊ฒ ์ง๋งโฆ)
Leave a comment