[Cmoney 菁英软体工程师战斗营] IOS APP 菜鸟开发笔记(7)----自定义弹出视窗

前言

因为UI和UX方面的需求,这几天上网搜寻了如何自定义下一页的弹出大小,弹出位置和动画,发现有蛮多种方法都能达到成,于是选了个来实作。因为目前的进度压力比较大,所以很多地方没有写得有弹性和封装好,再请见谅了。

首先我们来设计一个由下往上弹出的页面,自定义的部分为弹出后的高度,这边用protocol来让其他类修改。

public protocol PresentBottomVCProtocol {    var controllerHeight: CGFloat {get}}

再来要写一个继承 UIPresentationController 的类,里面可以添加动画和遮罩效果。

public class PresentBottom:UIPresentationController {    ///  黑色遮罩    lazy var blackView: UIView = {        let view = UIView()        if let frame = self.containerView?.bounds {            view.frame = frame        }        view.backgroundColor = UIColor.black.withAlphaComponent(0.4)        let gesture = UITapGestureRecognizer(target: self, action: #selector(sendHideNotification))        view.addGestureRecognizer(gesture)        return view    }()        /// 调整高度    public var controllerHeight:CGFloat        public override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {        //get height from an objec of PresentBottomVC class        if case let vc as PresentBottomVC = presentedViewController {            controllerHeight = vc.controllerHeight        } else {            controllerHeight = UIScreen.main.bounds.width        }        super.init(presentedViewController: presentedViewController, presenting: presentingViewController)    }    //    /// 在弹窗即将出现时把遮罩添加到containerView,并通过动画将遮罩的alpha设置为1    public override func presentationTransitionWillBegin() {        blackView.alpha = 1        containerView?.addSubview(blackView)    }    ///  在弹窗即将消失时做的事    public override func dismissalTransitionWillBegin() {            }    /// 在弹框消失之后将遮罩从containerView上移除    public override func dismissalTransitionDidEnd(_ completed: Bool) {        if completed {            blackView.removeFromSuperview()        }    }        ///   决定了弹出框的frame, 它决定了弹出框在屏幕中的位置,由于我们是底部弹出框,我们设定一个弹出框的高度controllerHeight,即可得出弹出框的frame    public override var frameOfPresentedViewInContainerView: CGRect {        return CGRect(x: 0, y: UIScreen.main.bounds.height-controllerHeight, width: UIScreen.main.bounds.width, height: controllerHeight)    }        extension UIViewController: UIViewControllerTransitioningDelegate {        /// - Parameter vc: class name of bottom view      public func presentBottom(_ vc: PresentBottomVC ) {        vc.modalPresentationStyle = .custom        vc.transitioningDelegate = self        vc.modalTransitionStyle = UIModalTransitionStyle.coverVertical //由下跳转的动画        self.present(vc, animated: true, completion: nil)    }        /// - Parameter vc: class name of bottom view    public func presentMiddle(_ vc: PresentMiddleVC ) {        vc.modalPresentationStyle = .custom        vc.transitioningDelegate = self        vc.modalTransitionStyle = UIModalTransitionStyle.crossDissolve //直接跳转的动画        self.present(vc, animated: true, completion: nil)    }                // function refers to UIViewControllerTransitioningDelegate    public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {                if  case let vc as PresentBottomVC = presented {            let present = PresentBottom(presentedViewController: vc, presenting: presenting)            return present        }else if case let vc2 as PresentMiddleVC = presented{            let present = PresentMiddle(presentedViewController: vc2, presenting: presenting)            return present        }       return nil    }}

接下来设计一个基底类实现刚才写的protocol

public let PresentBottomHideKey = "ShouldHidePresentBottom"public class PresentBottomVC: UIViewController, PresentBottomVCProtocol {    public var controllerHeight: CGFloat {        return 0    }        public override func viewDidLoad() {        super.viewDidLoad()        NotificationCenter.default.addObserver(self, selector: #selector(presentBottomShouldHide), name: NSNotification.Name(PresentBottomHideKey), object: nil)    }        public override func viewDidDisappear(_ animated: Bool) {        super.viewDidDisappear(animated)        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(PresentBottomHideKey), object: nil)    }        @objc func presentBottomShouldHide() {        self.dismiss(animated: true, completion: nil)    }    }

以后我们只要让新的 Controller 继承 PresentBottomVC 并覆写controllerHeight后,就能愉快地设定弹出后的高度了!

class TestViewController:  PresentBottomVC {    override var controllerHeight: CGFloat {        return screenSize.height*4/7    }

如果要设定弹出在画面中间,类似 AlertView 的弹出视窗,也可以照以上流程设计。在上方的UIViewControllerTransitioningDelegate 那可以设定弹出的动画效果,以及外界该如何呼叫我们的弹出视窗。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章