기어가더라도 제대로
[SwiftUI-기초] Animation 기본 본문
withAnimation { } 도 물론 있지만, 숨겨져 있는 Animation modifier 들을 알아보자.
Button에 붙이는 애니메이션
- 빨간색 원을 만들고 버튼을 누를 때마다 크기가 늘어나도록 설정을 해봄
- . scaleEffect() : 이 모디파이어를 사용해서 버튼의 크기를 조절할 것임
struct ContentView: View {
@State private var animationAmount = 1.0
var body: some View {
Button("Tap Me") {
animationAmount += 1
}
.padding(50)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
.scaleEffect(animationAmount)
}
}
- 0에서 1 사이의 값을 전달할 수 있음
- animationAmount의 값이 0 이면 버튼이 사라지고 1이면 버튼이 원래 크기
- 여기서 버튼을 누를 때 animationAmount에 1의 값을 더하면 두 배의 크기로 늘어남
animation
.animation(.default, value: animationAmount)
- 스케일이 커지는 상황을 동적으로 표현함
- .default 대신 사용할 수 있는 값들이 있는데 이따 알아보도록 하겠음
blur
- 흐릿하게 하는 효과를 줍니다.
- 버튼을 한번 눌렀을 때, 흐릿해진 모습
Button("Tap Me") {
animationAmount += 1
}
.padding(50)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
.scaleEffect(animationAmount)
.blur(radius: (animationAmount - 1) * 3)
.animation(.default, value: animationAmount)
- .animation modifier 앞에 동적으로 변화할 속성들이 먼저 선언되어 있어야 변화가 애니메이션이 됨
- .blur 에 radius 같은 경우, 기본 값인 1인 경우엔, 가장 0이니까 가장 선명하고 한번 탭할 때마다 3배씩 흐릿해짐
Animation Variation
- .default 대신 사용할 수 있는 값들이 있음
- .easeOut: 빠르게 늘어나고 끝부분에 올쯤 속력이 줄음
- .interpolatingSpring: 용수철 효과
.animation(.interpolatingSpring(stiffness: 50, damping: 1), value: animationAmount)
- stiffness: 초기에 스프링이 응축된 정도, 즉 튕기는 속도를 조절
- damping: 값이 낮을수록 더 오래 댕겅 거림
- .default 와 같은 요소도 animation 이기 때문에 자체에 지속시간을 달 수 있음
.animation(.easeInOut(duration: 2), value: animationAmount)
- 딜레이 : 1초 후에 2초 동안 애니메이션 실시
.animation(
.easeInOut(duration: 2)
.delay(1),
value: animationAmount
)
- 되돌아오기(?) Auto reverse
.animation(
.easeInOut(duration: 1)
.repeatCount(3, autoreverses: true),
value: animationAmount
)
- 원형으로 늘어났다가 줄어들었다가 다시 늘어난다.
- 3에서 2로 변경되면 늘어났다가 줄어들었다가 까지는 애니메이션이 적용되고, 변화 후의 크기만큼은 애니메이션이 적용 안된 채로 늘어남
- 계속 반복
- 아예 계속 반복시킴
.animation(
.easeInOut(duration: 1)
.repeatForever(autoreverses: true),
value: animationAmount
)
Animation variation 2
- 파문을 그리면서 파동형으로 번져나가는 애니메이션을 해볼 것임
- 기존에 애니메이션을 지우고 overlay라는 것을 사용
.overlay(
Circle()
.stroke(.red)
.scaleEffect(animationAmount)
.opacity(2 - animationAmount)
.animation(
.easeOut(duration: 1)
.repeatForever(autoreverses: false),
value: animationAmount
)
)
- 현행은 버튼을 한번 눌러줘야 파동이 늘어나는데, .onAppear() 되자마자 바로 파동이 보이도록 하고 싶다면..
Button("Tap Me") {
animationAmount += 1
}
.padding(50)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
.overlay(
Circle()
.stroke(.red)
.scaleEffect(animationAmount)
.opacity(2 - animationAmount)
.animation(
.easeOut(duration: 1)
.repeatForever(autoreverses: false),
value: animationAmount
)
)
.onAppear {
animationAmount = 2
}
View 의 변화를 암묵적으로 애니메이이션 주기
- .animation() 같은 바인딩은 거의 모든 SwiftUI 오브젝트에 적용할 수 있음
- @State 의 변화를 감지해서 기존의 뷰에 변화를 적용할 상태를 감지하고, 변화 후에 상태를 반영하기 때문임
- 말이 어려우니 직접 보도록하자.
- 전에 예제에서 stepper 를 달건데, 여기만 애니메이션을 주고, button 에는 안주고 싶음.
struct ContentView: View {
@State private var animationAmount = 1.0
var body: some View {
print(animationAmount)
return VStack {
Stepper("Scale amount", value: $animationAmount.animation(), in: 1...10)
Spacer()
Button("Tap Me") {
animationAmount += 1
}
.padding(40)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
.scaleEffect(animationAmount)
}
}
}
- 문법이 조금 변경되었다.
- Print 는 뷰와 관련이 없는 코드여서 Body 가 오인을 할 수 있으니,
VStack 부분이 View 에 관계된 부분이라고 명시적으로 return 으로 알려주었음 - 이 코드의 요지는 stepper 의 value 값이 변화하는 것을 animation 을 줄 수 있다는 것임
- binding 에 animation 을 걸어주었는데, 딜레이나, 마찬가지로 걸어줄 수 있다.
Stepper("Scale amount", value: $animationAmount.animation(
.easeInOut(duration: 1)
.repeatCount(3, autoreverses: true)
), in: 1...10)
명시적으로 애니메이션 주기
다시 말하지만, SwiftUI에서 애니메이션 효과를 주는 방식에는 3가지가 있다.
- 암시적인 방법
- View에 .animation() modifier 를 달기
- Binding에 .animation() modifier 사용하기
- 명시적인 방법
- withAnimation { } 에 변화를 주기
또한, binding 과 withAnimation 이 애니메이션을 주는 원리에 대해서 간단히 짚고 넘어가자면,
두 방법은 앱이 state 의 변화를 감지하면, 변화전의 값과 변화후의 값을 계산해 내고 해당 변화만큼 애니메이션을 줍니다.
즉, @State 변수에 값만 변화 시키면, 세부적으로 어떤 방식으로 애니메이션을 그려라 라는 명령을 내리지 않고, 자동적으로 그려준다는 것이지요.
명시적인 방법에 대해서 알아봅시다.
struct ContentView: View {
@State private var animationAmount = 0.0
var body: some View {
Button("Tap Me") {
withAnimation {
animationAmount += 360
}
}
.padding(50)
.background(.red)
.foregroundColor(.white)
.clipShape(Circle())
.rotation3DEffect(.degrees(animationAmount), axis: (x: 1, y: 0, z: 0))
}
}
- 이번 실습을 도와줄 메서드는 .rotation3DEffect() 라는 친구입니다.
- 이 친구는 변화를 감지할 state를 하나 파라미터로 받습니다.
- 또 어떤 축을 기준으로 변화를 할지도 결정하는 axis라는 파라미터를 받습니다. 못을 박을 때, 그 축을 기준으로 회전하는 모습을 상상해보세요.
- x: 수평선을 기준으로 앞뒤로 회전합니다.
- y: 수직선을 기준으로 좌우로 회전합니다.
- z: 시계방향으로 왼쪽으로 오른쪽으로 스핀합니다.
withAnimation(.interpolatingSpring(stiffness: 5, damping: 1)) {
animationAmount += 360
}
- 애니메이션이다 보니 어떤 식으로 표현할지도 설정할 수 있습니다.
'SwiftUI - 기초' 카테고리의 다른 글
[SwiftUI-기초] custom transition (0) | 2022.10.31 |
---|---|
[SwiftUI-기초] Animation의 View적인 특성(+ Drag, transition) (0) | 2022.10.30 |
[SwiftUI-기초] View 생명주기, View 등장 시 실행 (0) | 2022.10.26 |
[SwiftUI-기초] String 과 작업하기 (0) | 2022.10.24 |
[SwiftUI-기초] Bundle 에서 Data 가져오기 (0) | 2022.10.23 |
Comments