ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [DevDiary] Custom Transition & CoreAnimation
    앱등이에게 살충제를 뿌린다./일기는 일기장에 2017. 6. 24. 10:08

    막바지에 다다르고 있는 프로젝트에서 UI Animation을 많이 경험할 수 있었다.

    사내에 Animation를 통해 UX/UI를 연구하는 부서가 있다보니 디테일한 요구사항이 많았고, 굉장히 이쁜 결과물을 얻을 수 있었다.


    1. Push/Pop/Present 애니메이션

    처음에는 굉장히 어려워 보였지만, UIViewControllerAnimatedTransitioning를 Implement하는 방법을 안다면 어떤 트랜지션효과도 무섭지가 않다.


    Present를 위한 트랜지션은 

    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? 

    Push/Pop을 위한 트랜지션은

    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? 

    메소드에서 UIViewControllerAnimatedTransitioning를 Implement한 객체를 return해주면 된다.


    참고 : https://www.raywenderlich.com/110536/custom-uiviewcontroller-transitions



    2. CAAnimation

    애니메이션 부서에서는 이런 요청을 했다. "0.3초간 이미지가 커지면서 Push가 종료됩니다."

    그래서 UIView.animationWithDuration(0.3 ....) 메소드를 호출하여 적용했다. 같이 Option파라미터까지 맞춰가면서 작업을 마무리했다.

    그러던 어느 날,, curve값을 custom timing function을 적용해달라는 요청이 왔다.

    구글링을 해보니, Core Animation을 써야 한단다.


    결론은 UIView.animatieWithDuration에 비해 코드양이 엄청나게 상승한다.

    Custom timing function 하나만을 위해서,, 하지만 막상 해놓고 나니 이뻐서 뿌듯했다.

    내가 어디가서 이런 애니메이션/인터렉션을 개발해보겠어?? 라는 생각도 들고..


    코드 공통화를 위해 아래 메소드들을 만들었다. 


        // Fade-In, Fade-Out 제공한다.

        class func fadeAnimation(fadeType: FadeAnimationType,

                                 duration: CFTimeInterval = 0.3,

                                 timingFunction: CAMediaTimingFunction) -> CAAnimation {

            let opacityAnimation = CABasicAnimation(keyPath: "opacity")

            opacityAnimation.fromValue = CGFloat(fadeType == .fadeIn ? 0 : 1)

            opacityAnimation.toValue = CGFloat(fadeType == .fadeIn ? 1 : 0)

            opacityAnimation.timingFunction = timingFunction

            opacityAnimation.repeatCount = 1

            

            return opacityAnimation

        }

        

        // 위치 이동을 제공한다.

        class func positionChangeAnimation(from fromPosition: CGPoint,

                                           to toPosition: CGPoint,

                                           duration: CFTimeInterval = 0.3,

                                           timingFunction: CAMediaTimingFunction) -> CAAnimation {

            let moveAnimation = CABasicAnimation(keyPath: "position")

            moveAnimation.fromValue = fromPosition

            moveAnimation.toValue = toPosition

            moveAnimation.timingFunction = timingFunction

            moveAnimation.repeatCount = 1

            

            return moveAnimation

        }

        

        // 크기 변경을 제공한다.

        class func resizeAnimation(from fromBounds: CGRect,

                                   to toBounds: CGRect,

                                   duration: CFTimeInterval = 0.3,

                                   timingFunction: CAMediaTimingFunction) -> CAAnimation {

            let resizeAnimation = CABasicAnimation(keyPath: "bounds")

            resizeAnimation.fromValue = fromBounds

            resizeAnimation.toValue = toBounds

            resizeAnimation.timingFunction = timingFunction

            resizeAnimation.repeatCount = 1

            

            return resizeAnimation

        }

        

        /**

         애니메이션 그룹을 편리하게 추가할 있게 도와주는 메소드.

         

         - Parameter isRemovedOnCompletion: 해당 필드를 false 하지 않으면 애니메이션이 끝난 뒤에, layer 속성이 원래대로 돌아간다.        왠만하면 false 계속 두고 쓰는게 좋다.

         */

        class func addGroupAnimation(to layer: CALayer,

                                     duration: CFTimeInterval,

                                     animations: [CAAnimation],

                                     isRemovedOnCompletion: Bool = false,

                                     completion: (() -> Void)? = nil) {

            for animation in animations {

                animation.duration = duration

            }

            

            let groupAnimation = CAAnimationGroup()

            groupAnimation.animations = animations

            groupAnimation.repeatCount = 1

            groupAnimation.duration = duration

            groupAnimation.fillMode = kCAFillModeForwards

            groupAnimation.isRemovedOnCompletion = isRemovedOnCompletion

            CATransaction.begin()

            CATransaction.setCompletionBlock {

                completion?()

            }


            layer.add(groupAnimation, forKey: "groupAnimation")

            

            CATransaction.commit()

        }



    아이린갓 보면서 끝~


Designed by Tistory.