1. 设置控制器属性
// 设置modal样式,弹出后原来的view不会消失,默认modal出来的控制器view会将原来的view移除
popoverVc.modalPresentationStyle = .custom
// 设置转场代理
popoverVc.transitioningDelegate = self
2. 设置转场代理方法
// MARK:- transitioningDelegate代理
extension GGHomeViewController : UIViewControllerTransitioningDelegate {
/// 目的:改变弹出view的frame,需要自定义UIPresentationController
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return GGPresentationController(presentedViewController: presented, presenting: presenting)
}
/// 目的:设置弹出动画
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresented = true // 由于弹出和消失用的是同一个协议,所需需要设置一个标志位来区分是弹出还是消失
return self
}
/// 目的:设置消失动画
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
isPresented = false
return self
}
}
2.1 自定义UIPresentationController
class GGPresentationController: UIPresentationController {
// MARK:- 懒加载属性
fileprivate lazy var coverView : UIView = UIView()
// MARK:- 系统函数回调
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
// 设置frame
presentedView?.frame = CGRect(x: 100, y: 55, width: 180, height: 250)
setupCoverView()
}
}
// MARK:- 设置蒙版
extension GGPresentationController {
fileprivate func setupCoverView() {
// 1. 添加蒙版
containerView?.insertSubview(coverView, at: 0)
// 2. 设置属性
coverView.frame = containerView!.bounds
coverView.backgroundColor = UIColor(white: 0.6, alpha: 0.2)
// 3. 给蒙版添加手势事件
let tabGes = UITapGestureRecognizer(target: self, action: #selector(GGPresentationController.coverViewTapGesClk))
coverView.addGestureRecognizer(tabGes)
}
}
// MARK:- 手势点击处理
extension GGPresentationController {
@objc fileprivate func coverViewTapGesClk() {
print("coverViewTapGesClk")
presentedViewController.dismiss(animated: true, completion: nil)
}
}
3. 设置弹出、消失动画的协议
// MARK:- UIViewControllerAnimatedTransitioning协议
extension GGHomeViewController : UIViewControllerAnimatedTransitioning {
/// 设置动画播放事件
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
/// 设置动画效果
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
isPresented ? animationToPresentedView(using: transitionContext) : animationToDismissedView(using: transitionContext)
}
// 弹出动画
fileprivate func animationToPresentedView(using transitionContext: UIViewControllerContextTransitioning) {
// 1. 获取弹出的view
let presentedView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
// 2. 添加view
transitionContext.containerView.addSubview(presentedView)
// 3. 设置动画
presentedView.transform = CGAffineTransform(scaleX: 1.0, y: 0.0)
presentedView.layer.anchorPoint = CGPoint(x: 0.5, y: 0) // 动画的开始位置
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
presentedView.transform = CGAffineTransform.identity
}) { (_) in
// 4. 完成动画
transitionContext.completeTransition(true)
}
}
// 消失动画
// 返回的对象是一个协议,直接设置成当前对象
fileprivate func animationToDismissedView(using transitionContext: UIViewControllerContextTransitioning) {
// 1. 获取弹出的view
let presentedView = transitionContext.view(forKey: UITransitionContextViewKey.from)!
// 2. 设置动画
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
presentedView.transform = CGAffineTransform(scaleX: 1.0, y: 0.001)
}) { (_) in
// 3. 完成动画
transitionContext.completeTransition(true)
}
}
}