[iOS] Animation 방법(UIViewPropertyAnimator)

728x90

 

 

이번 포스트에선 UIViewPropertyAnimator에 대해 알아 보도록 하겠습니다.

지난 포스트에서 알아봤듯이 UIView.animate는 Deprecated될 가능성이 높습니다. 따라서 프로젝트 타켓이 10이상인 프로젝트에서 애니메이션을 적용할때 UIViewPropertyAnimator를 사용하는걸 권장합니다.

 

 

특징

  • iOS 10 부터 사용가능
  • UIIView.animate를 대체하는 API
  • 애니메이션 상태(시작, 중지, 일시정지 등)를 제어할 수 있다.
  • Interactive Animation

 

Animation State

https://developer.apple.com/documentation/uikit/uiviewanimating

 

UIViewAnimating - UIKit | Apple Developer Documentation

The UIViewAnimating protocol defines the methods for implementing the basic flow control for animations, including the ability to start, stop, and pause animations. There are also several properties for reflecting the current state of the animation and for

developer.apple.com

 

  • 애니메이션을 생성하면 Inactive상태가 된다. (초기상태)
  • 애니메이션을 Start, Pause하면 Active상태가 된다.
  • Active상태에서 Finish하게 되면 Inactive상태로 된다.
  • Active상태에서 Stop을 하게되면 Stopped상태가 되는데, 여기서는 애니메이션이 완전히 Finish된 상태가 아니다.

 

UIViewPropertyAnimator클래스를 이용하며, runningPropertyAnimator메서드를 이용하거나

UIViewPropertyAnimator 생성자를 이용해서 애니메이션을 적용합니다.

 

 

  • animator 생성

 

runningPropertyAnimator

var animator: UIViewPropertyAnimator?

@IBAction func start(_ sender: Any) {
  animator = UIViewPropertyAnimator.runningPropertyAnimator(
    withDuration: 3.0, delay: 0, options: [],
    animations: {
      self.animate()
  }, completion: { position in
    switch position {
    case .current:
      print("current")
    case .start:
      print("start")
    case .end:
      print("end")
    }
  })
}

 

 

UIViewPropertyAnimator 생성자

@IBAction func start(_ sender: Any) {
  // curve 파라미터에는 easeInOut, easeIn, easeOut, linear 옵션을 사용할 수 있다.
  animator = UIViewPropertyAnimator(duration: 3.0, curve: .linear) {
    self.animate()
  }

  // completion handler가 따로 없어서 필요하면 추가할 수 있다.
  animator?.addCompletion({ position in
    switch position {
    case .current:
      print("current")
    case .start:
      print("start")
    case .end:
      print("end")
    }
  })

  // 생성자로 애니메이션을 추가하면 꼭 startAnimation을 호출해야 애니메이션이 시작된다.
  animator?.startAnimation()
}

UIView.animate와 같은 파라미터를 갖지만 completion의 타입이 UIView.animate때와 다릅니다.

UIView.animate의 completion은 애니메이션의 성공여부인 Boolean의 타입이였다면,

UIViewPropertyAnimator의 completion타입은 종료된 위치의 상태값을 타나내는 열거형(current, start, end)이 전달됩니다.

 

  • animator 중지
@IBAction func pause(_ sender: Any) {
  animator?.pauseAnimation()
}

 

  • animator (재)시작
@IBAction func resume(_ sender: Any) {
  animator?.startAnimation()
}

 

  • animator 정지
    • true를 전달하면 별도의 마무리 없이 정지되며, Inactive상태로 돌아간다.
    • false를 전달하면 완전이 애니메이션이 제거되지 않는 Stopped상태가 되기 때문에 보통 finishAnimation과 함께 사용된다.
    • finishAnimation이 호출되면 completion handler가 호출되고, Inactive상태로 전환되게 됩니다.
// true
animator.stopAnimation(true)

// false
animator.stopAnimation(false)
animator.finishAnimation(at: .current)

//---------------------------------------------//

@IBAction func stop(_ sender: Any) {
  animator?.stopAnimation(false)
  animator?.finishAnimation(at: .current)
}

 

 

  • animator 추가

Stopped상태에서 추가하게되면 Crash가 발생한다.

반드시 Inactive, Active상태에서 애니메이션을 추가해야됩니다.

Active 상태에선 애니메이션이 추가되면 애니메이션중에 남은 시간동안 추가되고,

Inactive 상태에서 추가되면 처음부터 애니메이션이 추가된 상태로 애니메이션이 진행된다.

@IBAction func add(_ sender: Any) {
  animator?.addAnimations({
    self.objectView.backgroundColor = .blue
    self.objectView.frame = CGRect(x: 200, y: 200, width: 50, height: 50)
  }, delayFactor: 0)
}

 

  • Interactive Animation

UIViewPropertyAnimator는 fractionComplete를 통해 interactive 애니메이션 지원이 쉽게 가능합니다!

fractionComplete는 0과 1사이의 값을 가지며, 들어온 값에 의해 애니메이션이 자유롭게 바뀔수가 있다.

//Slider와 연결되있다고 가정할때
animator?.fractionComplete = CGFloat(sender.value)

 

 

전체 예제)

import UIKit

class PropertyAnimatorViewController: UIViewController {

  @IBOutlet weak var objectView: UIView!

  var animator: UIViewPropertyAnimator?

  func animate() {
    let targetFrame = CGRect(x: view.center.x - 150, y: view.center.y - 150, width: 300, height: 300)
    objectView.frame = targetFrame
  }

  @IBAction func start(_ sender: Any) {
    animator = UIViewPropertyAnimator.runningPropertyAnimator(
      withDuration: 3.0, delay: 0, options: [],
      animations: {
        self.animate()
    }, completion: { position in
      switch position {
      case .current:
        print("current")
      case .start:
        print("start")
      case .end:
        print("end")
      }
    })
  }

  @IBAction func pause(_ sender: Any) {
    animator?.pauseAnimation()
  }

  @IBAction func stop(_ sender: Any) {
    animator?.stopAnimation(false)
    animator?.finishAnimation(at: .current)
  }

  @IBAction func resume(_ sender: Any) {
    animator?.startAnimation()
  }

  @IBAction func add(_ sender: Any) {
    animator?.addAnimations({
      self.objectView.backgroundColor = .blue
      self.objectView.frame = CGRect(x: 200, y: 200, width: 50, height: 50)
    }, delayFactor: 0)

  }

  @IBAction func sliderChange(_ sender: UISlider) {
    animator?.fractionComplete = CGFloat(sender.value)
  }
 }

 

 

 

 

참조 : https://developer.apple.com/documentation/uikit/uiviewpropertyanimator