# Animation

SwiftUI에서 애니메이션은 animation 모디파이어만 전달하면 끝이다. 애니메이션 타입과 애니메이션 로직에 대응될 값을 전달한다.

Circle()
    .foregroundColor(.blue)
    .frame(width: 50, height: 50)
    .position(position)
    .offset(x: 50, y: 50)
    .animation(.easeInOut, value: position)

animation모디파이어에 전달되는 Animation 인스턴스에 여러 속성들을 추가적으로 부여할 수 있다. duration을 부여하면 애니메이션 지속시간을 지정할 수 있다.

Circle()
    // ...
    .animation(.bouncy(duration: 1, extraBounce: 0.2), value: position)

애니메이션 동작에 추가적으로 모디파이어를 등록할 수 있는데, 애니메이션 대상 뷰에 등록하는 것이 아닌 애니메이션 내에 직접 추가하는 방식이다.

Circle()
    .animation(.easeInOut(duration: 1).delay(1) /* 여기 */ , value: position)

애니메이션의 speed모디파이어는 애니메이션 duration값과 곱하여 애니메이션을 처리하게 된다.

애니메이션 동작을 클로저 형태로 직접 지정할 수도 있다. withAnimation클로저를 사용하면 된다. withAnimation 파라미터를 통해 애니메이션 타입을 직접 지정할 수도 있다.

Button("Animate") {
    withAnimation {
        position = position == .zero ? CGPoint(x: 300, y: 500) : .zero
    }
}

// 버튼 애니메이션 직접 지정
Button("Animate") {
    withAnimation(.bouncy) {
        position = position == .zero ? CGPoint(x: 300, y: 500) : .zero
    }
}

# Repeat Animation

애니메이션 반복을 위해서는 애니메이션 인스턴스에 repeatCount , 혹은 repeatForever 모디파이어를 전달하면 된다.

var finiteRepeat: Animation {
    .linear(duration: 1.5)
    .repeatCount(3, autoreverses: false)
}

Image(systemName: "arrow.2.circlepath")
    .resizable()
    .foregroundColor(.blue)
    .aspectRatio(contentMode: .fit)
    .frame(width: 200, height: 200)
    .rotationEffect(.degrees(animating ? 360 : 0))
    .animation(finiteRepeat /* 반복 애니메이션 */, value: animating)

autoreverses는 디폴트로 true로 설정되어 있다. autoreverses가 true이면 애니메이션이 한 사이클 돌고 나서 제자리로 돌아가게 된다.

# Spring Animation

스프링 애니메이션은 세가지 파라미터로 속성을 정의할 수 있다.

Circle()
    .foregroundColor(.blue)
    .frame(width: 50, height: 50)
    .position(position)
    .offset(x: 50, y: 50)
    .animation(.spring(response: 0.8, dampingFraction: 0.1, blendDuration: 0), value: position)

response는 애니메이션의 지속시간을 나타낸다. dampingFraction은 스프링의 탄성을 나타내어 값이 작을수록 오랫동안 튕긴다.