Increate Readability For UIView Animation Code through UIView Extension.

Git 링크

본문

UIView의 animate()메소드 animations 클로저와 completion 클로저를 갖는 animate() 메소드를 사용하여 애니메이션 코드를 자주 사용하다보면 코드의 가독성이좀 떨어지며, 자동완성 기능을 사용해봤으면 알겠지만 좀불편 한 것을 많이 느낄 수 있다. 우리는 보통 아래와 같이 사용한다.

UIView.animate(withDuration: 3.0, delay: 1.0, options: [], animations: { [weak self] in

self?.boxView.backgroundColor = .brown
self?.boxView.frame.size.width += 10
self?.boxView.frame.size.height += 10
...
    }, completion: { finished in

...
})

trailing closure 문법을 이용하면 눈에 딱 잘 안들어온다.

UIView.animate(withDuration: 3.0, delay: 1.0, options: [], animations: { [weak self] in
self?.boxView.backgroundColor = .brown
self?.boxView.frame.size.width += 10
self?.boxView.frame.size.height += 10
...
}) { (finished) in
...
}

다음과 같이 animations 클로저와 completion 클로저를 변수에 저장해서 animate()함수에 파라미터로 전달하는 방법을 사용하면 그나마 괜찮지만 코드가 길어진다는 단점이 있다.

let animations = {
self?.boxView.backgroundColor = .brown
self?.boxView.frame.size.width += 10
self?.boxView.frame.size.height += 10
...
}
let completions = { finished in
...
}
UIView.animate(withDuration: 3.0, delay: 1.0, options: [], animations: animations, completion: completion)

애니메이션 코드의 가독성 및 자동완성을 쉽게 만드는 방법이 없을까? 아래와 같이 바꾼다면 가독성 및 자동완성기능을 더 효율적으로 만들 수 있다.

UIView.Animator(duration: 3.0)
.delay(1.0)
.options([])
.animations {
self?.boxView.backgroundColor = .brown
self?.boxView.frame.size.width += 10
self?.boxView.frame.size.height += 1
}
.completion { finished in
...
}
.animate()

플루이드 디자인패턴을 사용하여 애니메이션 코드의 가독성을 높였다. (메소드에서 자신의 주소 Self를 리턴하여 계속해서 자신에 접근할 수 있게 하는 패턴)

한 번 만들어보자.

extension UIView {
class Animator {
typealias AnimationsBlock = () -> Void
typealias CompletionBlock = (Bool) -> Void
fileprivate var _animations: AnimationsBlock
fileprivate var _completion: CompletionBlock?
fileprivate var _duration: TimeInterval
fileprivate var _delay: TimeInterval
fileprivate var _options: UIViewAnimationOptions
   init(
duration: TimeInterval,
delay: TimeInterval = 0.0,
options: UIViewAnimationOptions = []) {

_duration = duration
_delay = delay
_options = options
_animations = {}
_completion = nil
}
   func delay(_ delay: TimeInterval) -> Self {
_delay = delay
return self
}
   func options(_ options: UIViewAnimationOptions) -> Self {
_options = options
return self
}

func animations(_ animations: @escaping AnimationsBlock) -> Self{
_animations = animations
return self
}
   func completion(_ completion: @escaping CompletionBlock) -> Self{
_completion = completion
return self
}

func animate() {
UIView.animate(
withDuration: _duration,
delay: _delay,
options: _options,
animations: _animations,
completion: _completion)
}
}
}

Spring 애니메이션도 사용하고 싶다면 아래와 같이 기존에 만들어놓은 Animator 클래스를 상속시킨 SpringAnimator 클래스를 UIView에 확장시키면 된다.

extension UIView {
class SpringAnimator: Animator {
fileprivate var _damping: CGFloat
fileprivate var _velocity: CGFloat

init(
duration: TimeInterval,
delay: TimeInterval = 0.0,
damping: CGFloat = 0.1,
velocity: CGFloat = 0.1,
options: UIViewAnimationOptions = []) {
_damping = damping
_velocity = velocity
super.init(
duration: duration, delay: delay, options: options)
    }

func damping(_ damping: CGFloat) -> Self {
_damping = damping
return self
}

func velocity(_ velocity: CGFloat) -> Self {
_velocity = velocity
return self
}

override func animate() {
UIView.animate(
withDuration: _duration,
delay: _delay,
usingSpringWithDamping: _damping,
initialSpringVelocity: _velocity,
options: _options,
animations: _animations,
completion: _completion)
}
}
}

다음과 같이 사용할 수 있다.

UIView.SpringAnimator(duration: 3.0)
.damping(1.0)
.velocity(1.0)
.animations {
self.box.frame.size = CGSize(width: 100, height: 100)
}
.animate()

결론

간단하지만 UIView Animation 코드딴을 좋게 만들 수 있습니다. 유용하셨으면 좋겠습니다.

Like what you read? Give 손명기 a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.