UIKit / UIViewPropertyAnimator

iOS 앱개발 공부

목록 보기
3/30

🧠 핵심 개념

UIViewPropertyAnimator는 애니메이션을 '정의'하고, '시작하고', '일시정지'하거나 '취소'하고, '다시 시작'하는 등의 조작을 할 수 있는 객체이다.
이는 iOS 10부터 도입된 애니메이션 클래스로, 기존의 UIView.animate(...) 방식보다 더 유연하고 정밀한 애니메이션 제어를 가능하게 한다.

✅ 특징

  • 인터랙티브 애니메이션 가능 (예: 슬라이드, 드래그에 따라 진행도 조절)
  • 애니메이션 시작 시점 조절 가능 (startAnimation() 호출 전까지 실행 안 됨)
  • 여러 애니메이션 연속 결합 가능
  • 애니메이션 진행 상태(fractionComplete)를 직접 제어 가능

⭐️ 상태

UIViewPropertyAnimator는 애니메이션의 실행 상태에 따라 여러가지 상태를 가지게 되고, 그 특징은 아래와 같다.

상태설명호출 가능한 Method
Inactive애니메이션 시작 전startAnimation(), pauseAnimation()
Inactive(finished)애니메이션 완료-
Active애니메이션 실행 중pauseAnimation(), stopAnimation()
Active(paused)애니메이션 일시 정지 중continueAnimation()
Stopped애니메이션 중지 됨finishAnimation()

⚙️ 생성자 및 핵심 메소드

1) 생성자(initializers)

메소드설명
init(duration: TimeInterval, curve: UIView.AnimationCurve, animations: (() -> Void)?)기본적인 cubic curve 기반 애니메이터 생성
init(duration: TimeInterval, timingParameters: UITimingCurveProvider)UISpringTimingParameters 또는 UICubicTimingParameters를 사용해 고급 타이밍 설정 가능

2) 애니메이션 제어 관련 메소드

메소드설명
startAnimation()애니메이션 시작
pauseAnimation()애니메이션 일시 정지
stopAnimation(_:)애니메이션 중단 (true면 현재 위치 고정, false면 완료로 설정됨)
finishAnimation(at:)애니메이션을 특정 위치에서 종료
.current, .start, .end
continueAnimation(withTimingParameters:durationFactor:)일시 정지된 애니메이션을 이어서 재생 (다른 타이밍 파라미터로도 가능)

3) 애니메이션 블록 추가

메소드설명
addAnimations(_:)추가 애니메이션을 기존 애니메이션에 병합
addAnimations(_:delayFactor:)지연된 애니메이션을 병합
addCompletion(_:)애니메이션 완료 후 실행할 클로저 등록 (.start, .end, .current 위치 기반)

4) 프로퍼티

프로퍼티설명
state현재 애니메이터 상태 (inactive, active, stopped)
isRunning현재 애니메이션이 실행 중인지 여부
fractionComplete애니메이션 진행 비율 (0.0 ~ 1.0) — 인터랙티브 컨트롤에 사용
scrubsLinearlytrue면 fractionComplete가 정확한 비율대로 작동 (보통 true 사용)
reversed애니메이션을 반대로 실행

⚒️ 기본 사용 방법

let animator = UIViewPropertyAnimator(duration: 0.5, curve: .easeInOut) {
    view.alpha = 0.0
}
animator.startAnimation()

주요 파라미터

파라미터설명
duration애니메이션의 지속 시간
curve애니메이션 실행 곡선
timingParameters고급 타이밍 제어

여기서 curve는 애니메이션이 실행되는 형태를 설정하는 파라미터로, .easeInOut, .linear, .easeIn, easeOut 등이 대표적으로 사용된다. 각각의 속성마다 애니메이션이 실행되는 방식이 다르며, 그래프로 표현하자면 아래와 같다.

  • easeInOut: 시작과 끝은 천천히, 중간은 빠르게 진행되는 곡선. 자연스러운 동작에 적합
  • linear: 시간에 따라 균일하게 변화. 일정한 속도로 움직임
  • easeIn: 처음은 천천히, 점점 빨라지는 곡선. 점점 가속되는 효과를 줌
  • easeOut: 처음은 빠르다가 점점 느려짐. 감속 효과를 줌

다음으로 timingParameters가 있는데, 이는 주로 UISpringTimingParameters, UICubicTimingParameters 등을 사용한다. 이들은 애니메이션의 타이밍 곡선을 제어하는데 사용되며, UISpringTimimngParameters는 물리 기반 애니메이션을 제공하고 UICubicTimingParameters는 Bézier 곡선 기반 애니메이션을 제공한다.

특히, iOS의 경우 기본적으로 Spring 기반의 애니메이션을 사용하기 때문에 이를 잘 활용하면 더욱 iOS 스러운 앱을 만들 수 있다.

UISpringTimingParameters 특징 정리

  • 기반: 스프링 물리 엔진
  • 용도: 실감 나는 튕김 효과나 반동을 구현할 때 사용
  • 커스터마이징: dampingRatio, frequencyResponse, intialVelocity 등을 조정하여 커스텀 가능
  • 예시:
// -1 ~ 1 사이의 값. 탄력의 정도를 지정하는 값으로 값이 작을 수록 덜 튕김.
let springParams = UISpringTimingParameters(duration: 1, bounce: 0.5)

// 0 이상. 값이 클수록 출렁임이 줄어들고 1 이상은 출렁이지 않음
let springParams = UISpringTimingParameters(dampingRatio: 0.5)

// mass(질량), stiffness(강성), damping(강쇠), initialVelocity(초기 속도)에 따른 곡선
let springParams = UISpringTimingParameters(mass: 1, stiffness: 50, damping: 5, initialVelocity: .zero)

UICubicTimingParameters 특징 정리

  • 기반: Cubic Bézier 곡선 (UIKit 기본 .easeInOut, .easeIn, .easeOut, .linear 등)
  • 용도: 고정된 곡선을 따라 애니메이션을 부드럽게 진행시킴
  • 커스터마이징: 시작과 끝의 제어점을 직접 지정할 수 있음 (controlPoint1, controlPoint2)
  • 예시:
let cubicParams = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.42, y: 0.0),
                                          controlPoint2: CGPoint(x: 0.58, y: 1.0))
                                          
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: cubicParams)

그래프 예시(좌: UICubicTimingParameters, 우: UISpringTimingParameters)


🔥 고급 사용 예시

1. 진행률 제어

let animator = UIViewPropertyAnimator(duration: 1.0, curve: .linear) {
    view.frame.origin.x += 100
}

animator.pauseAnimation()      // 애니메이션 일시 정지
animator.fractionComplete = 0.5 // 절반 진행된 상태로 설정
animator.continueAnimation(withTimingParameters: nil, durationFactor: 1.0)

2. 제스처와 연동한 인터랙티브 애니메이션

var animator: UIViewPropertyAnimator!

func panGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
    let translation = recognizer.translation(in: view)
    let progress = min(max(translation.y / 200, 0), 1)

    switch recognizer.state {
    case .began:
        animator = UIViewPropertyAnimator(duration: 0.5, curve: .easeInOut) {
            myView.alpha = 0
            myView.transform = .identity
        }
        animator.pauseAnimation()

    case .changed:
        animator.fractionComplete = progress

    case .ended, .cancelled:
        if progress > 0.5 {
            animator.continueAnimation(withTimingParameters: nil, durationFactor: 1)
        } else {
            animator.isReversed = true
            animator.continueAnimation(withTimingParameters: nil, durationFactor: 1)
        }

    default:
        break
    }
}

✔️ 언제 쓰면 좋은가?

상황이유
제스처 기반 인터랙티브 애니메이션진행률을 직접 제어 가능
복잡한 타이밍 제어UISpringTimingParameters 등을 이용하여 자연스러운 움직임 가능
애니메이션을 나중에 시작startAnimation() 호출 전까지 지연 가능
중간에 애니메이션 조작 필요pauseAnimation(), continueAnimation(...) 등으로 유연하게 제어 가능

🧩 기존 UIView.animate()와 차이점

항목UIView.animate(...)UIViewPropertyAnimator
즉시 시작❌ (startAnimation() 필요)
인터랙션 제어
진행률 제어
중단 및 재시작
고급 타이밍 커스터마이징제한적매우 유연

🖋️ 결론

오늘은 UIViewPropertyAnimator라는 것을 학습했다.
항상 UIView.animate(...)만 사용했었는데, 이런 클래스가 있는 줄 정말 몰랐다...
기존에 쓰던 UIView.animate(...)와 달리 정교한 제어가 가능하고, 제스처 기반 인터랙션을 구현할 수 있다는 점에서 매력적이라고 생각했다.
간단한 애니메이션은 UIView.animate(...)를 사용해도 되겠지만, UX를 개선하고 보다 나은 앱을 만들기 위해서는 UIViewPropertyAnimator의 사용법을 잘 익히고 잘 사용할 줄 알아야겠다는 생각을 했다.

profile
이유있는 코드를 쓰자!!

0개의 댓글