本文代码基于swift4.0
实现效果如下:
这个提示框,是一个自定义的控制器。类似系统的UIAlertController。present出来的时候动画效果可自定义,弹框大小可自定义。
其步骤大致可分为3步:
- 定义一个自定义的XXPresentationController负责管理弹出控制器的大小,模式
import UIKit
class XXPresentationController: UIPresentationController {
let dimmingView = UIView()
override var shouldPresentInFullscreen: Bool {
return false
}
override var adaptivePresentationStyle: UIModalPresentationStyle {
return .overCurrentContext
}
override func size(forChildContentContainer container: UIContentContainer, withParentContainerSize parentSize: CGSize) -> CGSize {
return container.preferredContentSize
}
override var frameOfPresentedViewInContainerView: CGRect {
guard let containerView = containerView else {
return CGRect()
}
let containerBounds = containerView.bounds
var presentedViewFrame = containerBounds
presentedViewFrame.size = size(forChildContentContainer: presentedViewController, withParentContainerSize: containerBounds.size)
presentedViewFrame.origin.x = containerBounds.size.width / 2 - presentedViewFrame.size.width / 2
presentedViewFrame.origin.y = containerBounds.size.height / 2 - presentedViewFrame.size.height / 2
return presentedViewFrame
}
override func presentationTransitionWillBegin() {
dimmingView.backgroundColor = UIColor.black
dimmingView.alpha = 0.0
containerView?.insertSubview(dimmingView, at: 0)
guard let coordinator = presentedViewController.transitionCoordinator else {
return
}
coordinator.animate(alongsideTransition: { (_) in
self.dimmingView.alpha = 0.4
}, completion: nil)
}
override func dismissalTransitionWillBegin() {
guard let coordinator = presentedViewController.transitionCoordinator else {
return
}
coordinator.animate(alongsideTransition: { (_) in
self.dimmingView.alpha = 0.0
}) { (_) in
self.dimmingView.removeFromSuperview()
}
}
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
guard let containerView = containerView else {
return
}
//不能写dimmingView.bounds
dimmingView.frame = containerView.bounds
presentedView?.frame = frameOfPresentedViewInContainerView
}
}
- 定义一个自定义的class,服从UIViewControllerTransitioningDelegate协议。然后实现代理方法
import UIKit
class XXCustomTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return XXPresentationController(presentedViewController: presented, presenting: presenting)
}
//负责present时的动画效果
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let animator = XXCustomAnimator()
animator.isPresentation = true
return animator
}
//负责dismiss时的动画效果
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let animator = XXCustomAnimator()
animator.isPresentation = false
return animator
}
}
- 设置弹出控制器的transitioningDelegate 为自定义的类(这一步就类似于设置UITableView的代理)
import UIKit
class ViewController: UIViewController {
private var customTransitionDelegate: UIViewControllerTransitioningDelegate? //这个很重要,要是全局的。
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
@IBAction func customAlertButtonDidClicked(_ sender: UIButton) {
let alertVC = UIStoryboard.init(name: "XXAlert", bundle: nil).instantiateViewController(withIdentifier: "XXTipAlertVC") as! XXTipAlertVC
alertVC.titles = ("success", "yes", "no")
alertVC.notNowCallback = {
self.dismiss(animated: true, completion: nil)
}
alertVC.actionCallback = {
self.dismiss(animated: true, completion: nil)
}
alertVC.view.backgroundColor = UIColor.yellow
//不能写成alertVC.transitioningDelegate = XXCustomTransitionDelegate()
//注意customTransitionDelegate 不能在局部函数调用。要是全局的。
customTransitionDelegate = XXCustomTransitionDelegate()
alertVC.transitioningDelegate = customTransitionDelegate
present(alertVC, animated: true, completion: nil)
}
}
- 这里为了让弹出控制器有圆角,写了一个子类处理圆角,以及设置modalPresentationStyle = .custom
import UIKit
class CustomPopupVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
view.layer.cornerRadius = 12
view.layer.masksToBounds = true
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
initialization()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialization()
}
func initialization() {
modalPresentationStyle = .custom
}
}
-
alertVC是在storyBoard中绘制的简单的弹框
-
不过要注意一点,在storyBoard中记得设置ViewController的preferredContentSize。(XXPresentationController中是根据这个值来设置弹出控制器的大小)