Use UIPresentationController to write a neat, nice bottom popup control

A pop-up box at the bottom is a very common requirement in iOS App development. How to write a nice bottom popup box? There are many ways to do this. Adding a custom View to animate and hide it is a very simple operation, but it may seem a little less elegant. We can use the UIPresentationController to quickly and easily create a highly customized bottom popup. The official documentation address of UIPresentationController is as follows:

UIPresentationController: an object that manages the transition animations and the presentation of view controllers onscreen.

First, the final effect:

Making: github.com/IkeBanPC/Pr…

We need to use UIPresentationController in iOS8 and above. To use it, we need to create a new class that inherits UIPresentationController and rewrite the following methods and properties:

// Determines the frame of the popup
override var frameOfPresentedViewInContainerView

// Override this method to perform the desired action when the pop-up box is about to display
override func presentationTransitionWillBegin(a)

// Override this method to perform the desired action when the popbox finishes displaying
override func presentationTransitionDidEnd(_ completed: Bool)

// Override this method to perform the desired action when the popbox is about to disappear
override func dismissalTransitionWillBegin(a)

// Override this method to perform the desired action after the popup disappears
override func dismissalTransitionDidEnd(_ completed: Bool)
Copy the code

Override initialization method:

override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?). {super.init(presentedViewController:presentedViewController,presenting: presentingViewController)
}
Copy the code

Most of the time, we want the previous display area to be darker when the bottom popup appears, to emphasize that the display area of the popup is the primary area the user is currently working on. Therefore, we add a mask to this custom class:

lazy var blackView: UIView = {
    let view = UIView(a)if let frame = self.containerView? .bounds { view.frame = frame } view.backgroundColor =UIColor.black.withAlphaComponent(0.5)
    return view
}()
Copy the code

Rewrite presentationTransitionWillBegin, dismissalTransitionWillBegin and dismissalTransitionDidEnd (_ completed: Bool) method. Add the mask to containerView when the popover is about to appear, and animate the mask to alpha of 1; Set alpha of mask to 0 by animating when popover is about to disappear; Remove the mask from containerView after the cartridge disappears:

override func presentationTransitionWillBegin(a) {
    blackView.alpha = 0containerView? . AddSubview (blackLayerView)UIView.animate(withDuration: 0.5) {
        self.blackView.alpha = 1}}override func dismissalTransitionWillBegin(a) {
    UIView.animate(withDuration: 0.5) {
        self.blackView.alpha = 0}}override func dismissalTransitionDidEnd(_ completed: Bool) {
    if completed {
        blackView.removeFromSuperview()
    }
}
Copy the code

Next, we rewrite frameOfPresentedViewInContainerView this property. It determines the position of the popover on the screen. Since we are the bottom popover, we set the controllerHeight of the popover to get the frame of the popover:

override var frameOfPresentedViewInContainerView: CGRect {
    return CGRect(x: 0, y: UIScreen.main.bounds.height-controllerHeight, width: UIScreen.main.bounds.width, height: controllerHeight)
}
Copy the code

To make it easier for us to create various bottom pop-ups, we create a base class PresentBottomVC that inherits from UIViewController and add a property controllerHeight to get the height of the popup:

public class PresentBottomVC: UIViewController {
    public var controllerHeight: CGFloat? {
        get {
            return self.controllerHeight
        }
    }
}
Copy the code

After that, we can create a new class that inherits from PresentBottomVC and overwrites the controllerHeight property to customize the bottom popup. In order to convenient call pop-up method, we add an Extension to UIViewController, and implement UIViewControllerTransitioningDelegate protocol:

public func presentBottom(_ vc: PresentBottomVC.Type) {
    let controller = vc.init()
    controller.modalPresentationStyle = .custom
    controller.transitioningDelegate = self
    self.present(controller, animated: true, completion: nil)}public func presentationController(forPresented presented: UIViewController, presenting: UIViewController? , source: UIViewController) -> UIPresentationController? {
    let present = PresentBottom(presentedViewController: presented, presenting: presenting)
    return present
}
Copy the code

As you can see, all viewcontrollers that inherit from PresentBottomVC can pop up from the bottom of another ViewController using this method. For example, let’s create a new class FirstBottomVC, override controllerHeight and set it to 200, and add a close button to the page:

final class FirstBottomVC: PresentBottomVC {
    lazy var closeButton:UIButton = {
        let button = UIButton(frame: CGRect(x: 15, y: 30, width: 80, height: 30))
        button.setTitle("Close".for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.addTarget(self, action: #selector(closeButtonClicked), for: .touchUpInside)
        return button
    }()
    override var controllerHeight: CGFloat? {
        return 200
    }
    override func viewDidLoad(a) {
        super.viewDidLoad()
        view.backgroundColor = .cyan
        view.addSubview(closeButton)
    }
    @objc func closeButtonClicked(a) {
        self.dismiss(animated: true, completion: nil)}}Copy the code

Then call UIViewController’s presentBottom(_ vc: PresentBottomvc.type) method when you need to pop up and you’re done with one line of code:

self.presentBottom(FirstBottomVC.self)
Copy the code

The effect is shown below:

Test with the popup box written, we just according to their needs to create a different PresentBottomVC subclass can quickly and easily achieve a variety of bottom popup box. The two effects in this example can be found in the GitHub source