Custom navigation trainsition iOS

Là một Developer iOS thì ai cũng quen với UINavigationController và chúng ta thường quen với các animation default. Nhưng với một số thiết kế đặc biệt chúng ta cần phải custom animation cho view controller transition.

Để custom view controller transition bạn cần hiểu về UIViewControllerAnimatedTransitioning

I. Overview UIViewControllerAnimatedTransitioning

UIViewControllerAnimatedTransitioning là một protocol cho phép bạn implement các animation cho custom view controller transition

Để implement protocol này thì có 2 việc ta cần phải làm

  • Xác định duration cho animation bằng func
func transitionDuration( using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
  • Thực hiện animation traisition cho custom view controller
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
  • UIViewControllerContextTransitioning bao gồm tất cả thông tin về transitioning như: toView, fromView, containerView…

Như vậy để custom view controller transition nó sẽ gói gọn trong func animateTransition

II. Sử dụng UIViewControllerAnimatedTransitioning cho custom view controller transition

Ở đây tôi sẽ hướng dẫn các bạn thực hiện custom animation push và pop thành animation của present(push -> bottom to top và pop -> top to bottom)

1. Tạo enum cho NavigationTransitionStyle

enum NavigationTransitionStyle {
    case nomal
    case bottom
}
  • nomal: transition mặc định
  • bottom: custom animation transition từ bottom to top cho push và ngược lại cho pop

2. Tạo class implement UIViewControllerAnimatedTransitioning

Để hỗ trợ cho pop và push ta cần define các variable như sau:

class CustomNavigationAnimationTransition: NSObject, UIViewControllerAnimatedTransitioning {
    var popStyle: Bool = false
       var navigationStyle: NavigationTransitionStyle = .nomal
}
  • popStyle: flag để xác định là pop hay push
  • navigationStyle: xác định animation dạng nomal hay bottom

2.1 Cài đặt duration cho animation

    func transitionDuration( using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.5
    }

2.2 Cài đặt method animationTransition cho view controller

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
}
  • Điều hướng nếu là pop thì chúng ta sẽ xử lý animation pop ở method animatePop
if popStyle {
    animatePop(using: transitionContext)
    return
}
  • Thực hiện get các variable cần thiết để animation view controller: fromView, toView, frameTransition, frameOffset
let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
let frameTransition = transitionContext.finalFrame(for: toView)
var frameOffset = frameTransition.offsetBy(dx: 0, dy: frameTransition.height)
if navigationStyle == .nomal {
     frameOffset = frameTransition.offsetBy(dx: frameTransition.width, dy: 0)
}
  • Set frame cho toView và insert toView, fromView vào trong containerView
toView.view.frame = frameOffset
transitionContext.containerView.insertSubview(toView.view, aboveSubview: fromView.view)
  • Thực hiện animation bottom to top cho push
UIView.animate( withDuration: transitionDuration(using: transitionContext),
                animations: {
                    toView.view.frame = frameTransition
                },
                completion: {_ in
                    transitionContext.completeTransition(true)
                })

2.3 Cài đặt method animatePop

Tương tự như ở method animationTransition ở đây ta sẽ bỏ bước set frame cho toView và thực hiện animation cho fromView

func animatePop(using transitionContext: UIViewControllerContextTransitioning) {

        let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!
        let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!

        let frameTransition = transitionContext.initialFrame(for: fromView)
        var frameOffset = frameTransition.offsetBy(dx: 0, dy: frameTransition.height)
        if navigationStyle == .nomal {
            frameOffset = frameTransition.offsetBy(dx: frameTransition.width, dy: 0)
        }
        transitionContext.containerView.insertSubview(toView.view, belowSubview: fromView.view)

        UIView.animate( withDuration: transitionDuration(using: transitionContext),
                        animations: {
                            fromView.view.frame = frameOffset
                        },
                        completion: {_ in
                            transitionContext.completeTransition(true)
                        })
}

3. Sử dụng CustomNavigationAnimationTransition trong view controller

  • Khỏi tạo variable custom animation bên trên
private let navigationAnimationTransition = CustomNavigationAnimationTransition()
  • Sau đó config navigationStyle cho view controller và set delegate cho navigation controller
navigationAnimationTransition.navigationStyle = .bottom
navigationController?.delegate = self
  • Implement UIViewControllerTransitioningDelegate trong view controller
extension ViewController: UIViewControllerTransitioningDelegate {
    func navigationController(
        _ navigationController: UINavigationController,
        animationControllerFor operation: UINavigationController.Operation,
        from fromVC: UIViewController,
        to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        navigationAnimationTransition.popStyle = (operation == .pop)
        return navigationAnimationTransition

    }
}

Như vậy chúng ta vừa mới hoàn thành custom view controller transition. Ngoài cách tạo animation như trên thì bạn có thể làm bất cứ dạng animation nào mà bạn muốn.

Tài liệu tham khảo: https://developer.apple.com/documentation/uikit/uiviewcontrolleranimatedtransitioning

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.