IOS实战之自定义转场动画详解

2020-01-14 20:18:51丽君

 


class CustomPresentationController: UIPresentationController, UIViewControllerTransitioningDelegate {
  var presentationWrappingView: UIView? // 这个视图封装了原视图,添加了阴影和圆角效果
  var dimmingView: UIView? = nil // alpha为0.5的黑色蒙版

  // 告诉UIKit为哪个视图添加动画效果
  override func presentedView() -> UIView? {
    return self.presentationWrappingView
  }
}

// 四个方法自定义转场动画发生前后的操作
extension CustomPresentationController {
  override func presentationTransitionWillBegin() {
    // 设置presentationWrappingView和dimmingView的UI效果
    let transitionCoordinator = self.presentingViewController.transitionCoordinator()
    self.dimmingView?.alpha = 0
    // 通过转场协调器执行同步的动画效果
    transitionCoordinator?.animateAlongsideTransition({ (context: UIViewControllerTransitionCoordinatorContext) -> Void in
      self.dimmingView?.alpha = 0.5
      }, completion: nil)
  }

  /// present结束时,把dimmingView和wrappingView都清空,这些临时视图用不到了
  override func presentationTransitionDidEnd(completed: Bool) {
    if !completed {
      self.presentationWrappingView = nil
      self.dimmingView = nil
    }
  }

  /// dismiss开始时,让dimmingView完全透明,这个动画和animator中的动画同时发生
  override func dismissalTransitionWillBegin() {
    let transitionCoordinator = self.presentingViewController.transitionCoordinator()
    transitionCoordinator?.animateAlongsideTransition({ (context: UIViewControllerTransitionCoordinatorContext) -> Void in
      self.dimmingView?.alpha = 0
      }, completion: nil)
  }

  /// dismiss结束时,把dimmingView和wrappingView都清空,这些临时视图用不到了
  override func dismissalTransitionDidEnd(completed: Bool) {
    if completed {
      self.presentationWrappingView = nil
      self.dimmingView = nil
    }
  }
}

extension CustomPresentationController {
}

除此以外,这个类还要处理子视图布局相关的逻辑。它作为动画代理,还需要为动画提供animator对象,详细代码请在demo的Custom Presentation文件夹下阅读。

UINavigationController转场动画
到目前为止,所有转场动画都是适用于present和dismiss的,其实UINavigationController也可以自定义转场动画。两者是平行关系,很多都可以类比过来:


class FromViewController: UIViewController, UINavigationControllerDelegate {
  let toViewController: ToViewController = ToViewController()

  override func viewDidLoad() {
    super.viewDidLoad()
    setupView() // 主要是一些UI控件的布局,可以无视其实现细节

    self.navigationController.delegate = self
  }
}

与present/dismiss不同的时,现在视图控制器实现的是UINavigationControllerDelegate协议,让自己成为navigationController的代理。这个协议类似于此前的UIViewControllerTransitioningDelegate协议。