Làm thế nào để swipeback và detect action swipe của viewcontroller ở trong Navigation. Bởi default, khi add 1 viewcontroller vào Navigation thì chức năng swipe sẽ được tự động enable. Tuy nhiên, trong trường hợp mình custom nút back thì chức năng này sẽ bị disable. Vậy để có thể enable chức năng này, thì mình làm như sau:

InteractivePopGestureRecognizer

Để enable swipeback, đơn giản chỉ cần:

navigationController?.interactivePopGestureRecognizer?.delegate = self
navigationController?.interactivePopGestureRecognizer?.isEnabled = true

Tuy nhiên, để dễ dàng cho việc xử dụng, mình làm như sau: Tạo protocol VCInNavigation:

protocol VCInNavigation {

    var numberVCInNav: Int? { get }

    func delegateSwipeBack(of viewController: UIViewController?, to delegate: UIViewController?)

    func enableSwipeBack(enable: Bool, for viewController: UIViewController?)

    func viewWillSwipeBack()
}
  • numberVCInNav : Số lượng viewcontrollers nằm trong Navigation stack
  • delegateSwipeBack : chỉ định viewcontroller delegate
  • enableSwipeBack : Enable/disable swipeback
  • viewWillSwipeBack : Hàm detect sự kiện swipeback

Implement VCInNavigation protocol :

extension VCInNavigation where Self: UIViewController {

    var numberVCInNav: Int? {
        return self.navigationController?.viewControllers.count
    }

    func delegateSwipeBack(of viewController: UIViewController?, to delegate: UIViewController?) {
        viewController?.navigationController?.interactivePopGestureRecognizer?.delegate = delegate
    }

    func enableSwipeBack(enable: Bool, for viewController: UIViewController?) {
        viewController?.navigationController?.interactivePopGestureRecognizer?.isEnabled = enable
    }
}

Detect swipeback action

Để detect được action khi swipeback viewcontroller, thì mình phải implement UIGestureRecognizerDelegate :

extension UIViewController: UIGestureRecognizerDelegate {

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {

            (self as? VCInNavigation)?.viewWillSwipeBack()
        }
        return true
    }
}

  • Đối với các controller thoả mãn VCInNavigation protocol thì viewWillSwipeBack mới đc call khi thực hiện action swipeback

Cách sử dụng

Đơn giản là chỉ cần adopt protocol VCInNavigation và thực hiện set delegate hay enable/disable swipeback là xong

class BaseViewController: UIViewController, VCInNavigation {

    // MARK: - IBOutlet

    // MARK: - Varialbes

    // MARK: - View Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

       // create back button
        self.createBackButton()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // set delegate
        self.delegateSwipeBack(of: self, to: self)
        
        // enable/disable swipeback
        if let count = self.numberVCInNav, count > 1 {
            self.enableSwipeBack(enable: true, for: self)
        } else {
            self.enableSwipeBack(enable: false, for: self)
        }
    }

    func viewWillSwipeBack() {
        logD("\(String(describing: self))")
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    deinit {
        logD("\(String(describing: self))")
    }

    // MARK: - Setup View

    // MARK: - Actions

    // MARK: - Call Api

    // MARK: - Functions

}