用UIPresentationController来写一个简洁漂亮的底部弹出控件
2018-03-26 00:00
323 查看
点击上方“[b]iOS开发[/b]”,选择“置顶公众号”关键时刻,第一时间送达!
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_jpg/ow6przZuPIG18kzbzliaybJA5y49s2zn9OVOziayVbGUmujwPYZLVGmbMalFKZr8GstdMVntUWN6NVaibmrbsQR4w/640?wxfrom=5&wx_lazy=1)
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_gif/8RTSPr4mlymeeDuqGvOToCf0rvibQickeRsEibQevnVTpac8WEEr8yTTdVia8lGDM0JoAdg7Os86jhcnn6bpyInic9A/640?wx_fmt=gif&wxfrom=5&wx_lazy=1)
iOS App开发过程中,底部弹出框是一个非常常见的需求。如何写一个漂亮的底部弹出框呢?方式有很多,直接添加一个自定义的View让它动画展示和隐藏都是一种非常简单的操作,不过看起来似乎不那么优雅,我们可以使用UIPresentationController来方便快捷地创建一个高定制化的底部弹出框。UIPresentationController的官方文档地址如下:
UIPresentationController(https://developer.apple.com/documentation/uikit/uipresentationcontroller) : an object that manages the transition animations and the presentation of view controllers onscreen.
先上最终效果:
![](https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_gif/foPACGrddJ0VAX31F7o5IXNHX4wXznhclUwIrsR5FQTT0gNNzQofPsGNB93fAvBMCNFic7BLiaQxotWjkEdKJEow/640?wx_fmt=gif)
![](https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_gif/foPACGrddJ0VAX31F7o5IXNHX4wXznhcNtVTV5iaMyicK9jCpo2ch7ajWIeRMjkboibs0YmfB0DjicicU1hWibMyOczw/640?wx_fmt=gif)
GitHub: https://github.com/IkeBanPC/PresentBottom我们需要在iOS8及以上的系统中使用UIPresentationController,使用时需要新建一个类继承UIPresentationController并重写以下几个方法和属性:
//决定了弹出框的frameoverride var frameOfPresentedViewInContainerView
//重写此方法可以在弹框即将显示时执行所需要的操作override func presentationTransitionWillBegin()
//重写此方法可以在弹框显示完毕时执行所需要的操作override func presentationTransitionDidEnd(_ completed: Bool)
//重写此方法可以在弹框即将消失时执行所需要的操作override func dismissalTransitionWillBegin()
//重写此方法可以在弹框消失之后执行所需要的操作override func dismissalTransitionDidEnd(_ completed: Bool)
重写初始化方法:
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { super.init(presentedViewController:presentedViewController,presenting: presentingViewController)}
在大多数时候,我们希望底部弹出框出现时,先前的显示区域能够灰暗一些,来强调弹出框的显示区域是用户当前操作的首要区域。因此,我们给这个自定义的类添加一个遮罩:
lazy var blackView: UIView = { let view = UIView() if let frame = self.containerView?.bounds { view.frame = frame } view.backgroundColor = UIColor.black.withAlphaComponent(0.5) return view}()
重写presentationTransitionWillBegin、dismissalTransitionWillBegin和dismissalTransitionDidEnd(_ completed: Bool)方法。在弹窗即将出现时把遮罩添加到containerView,并通过动画将遮罩的alpha设置为1;在弹窗即将消失时通过动画将遮罩的alpha设置为0;在弹框消失之后将遮罩从containerView上移除:
override func presentationTransitionWillBegin() { blackView.alpha = 0 containerView?.addSubview(blackLayerView) UIView.animate(withDuration: 0.5) { self.blackView.alpha = 1 }}
override func dismissalTransitionWillBegin() { UIView.animate(withDuration: 0.5) { self.blackView.alpha = 0 }}
override func dismissalTransitionDidEnd(_ completed: Bool) { if completed { blackView.removeFromSuperview() }}
接下来,我们重写frameOfPresentedViewInContainerView这个属性。它决定了弹出框在屏幕中的位置,由于我们是底部弹出框,我们设定一个弹出框的高度controllerHeight,即可得出弹出框的frame:
override var frameOfPresentedViewInContainerView: CGRect { return CGRect(x: 0, y: UIScreen.main.bounds.height-controllerHeight, width: UIScreen.main.bounds.width, height: controllerHeight)}
为了便于我们创建各种各样的底部弹出框,我们创建一个基类PresentBottomVC继承自UIViewController,并添加一个属性controllerHeight用于得到弹出框的高度:
public class PresentBottomVC: UIViewController { public var controllerHeight: CGFloat? { get { return self.controllerHeight } }}
之后,我们就可以新建继承自PresentBottomVC并重写controllerHeight属性的类来实现定制化底部弹出框。为了方便调用弹出方法,我们给UIViewController添加一个Extension,并实现UIViewControllerTransitioningDelegate协议:
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}
可以看到,所有继承自PresentBottomVC的ViewController都可以通过该方法来从另一个ViewController的底部弹出。例如,我们新建一个类FirstBottomVC,重写controllerHeight并设为200,在页面中添加一个关闭按钮:
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() { super.viewDidLoad() view.backgroundColor = .cyan view.addSubview(closeButton) } @objc func closeButtonClicked() { self.dismiss(animated: true, completion: nil) }}
之后在需要弹出的时候调用UIViewController的presentBottom(_ vc: PresentBottomVC.Type)方法就可以一句代码搞定啦:
self.presentBottom(FirstBottomVC.self)
效果如下图:
![](https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_gif/foPACGrddJ0VAX31F7o5IXNHX4wXznhcYMPfrK3dBT31GU58eS2WYC4hbQ4D6dxNq3SbCqYD5U9hsE5aHFHoibg/640?wx_fmt=gif)
测试用的弹框写好了,我们只要根据自己的需求去创建不同的PresentBottomVC的子类就可以方便快捷的实现各种各样的底部弹出框啦。实例中的两个效果可以参考GitHub源码(https://github.com/IkeBanPC/PresentBottom)
![](https://ss.csdn.net/p?http://mmbiz.qpic.cn/mmbiz_png/TWtGkwUapckh3mpakrDbSW8wA9icDkicxJx0WyJGMKyib6hq2N76bvoJMRUrHSPd8BCSYSrS6LA5Pl1DsTPgNKGsA/640?)
作者:IsaacPan
链接:https://juejin.im/post/5a9651d25188257a5911f666
iOS开发整理发布,转载请联系作者授权
![](https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_gif/8RTSPr4mlymeeDuqGvOToCf0rvibQickeR0ibXPicZJ0RMiaJFpk8TicHlOWYdvNurUov1l9wrSW8QB5MDqa9HMbKRAw/640?wx_fmt=gif)
![](https://ss.csdn.net/p?https://mmbiz.qpic.cn/mmbiz_gif/G1TofAf0fqgmKZQJjj39ceYg5aeBfPwxUaibqpUJfFp7R3GYWibpmFTrabicaljvDbtkkcPicCWwdMibzvkjR36bA2A/640?)
【点击成为Java大神】
iOS App开发过程中,底部弹出框是一个非常常见的需求。如何写一个漂亮的底部弹出框呢?方式有很多,直接添加一个自定义的View让它动画展示和隐藏都是一种非常简单的操作,不过看起来似乎不那么优雅,我们可以使用UIPresentationController来方便快捷地创建一个高定制化的底部弹出框。UIPresentationController的官方文档地址如下:
UIPresentationController(https://developer.apple.com/documentation/uikit/uipresentationcontroller) : an object that manages the transition animations and the presentation of view controllers onscreen.
先上最终效果:
GitHub: https://github.com/IkeBanPC/PresentBottom我们需要在iOS8及以上的系统中使用UIPresentationController,使用时需要新建一个类继承UIPresentationController并重写以下几个方法和属性:
//决定了弹出框的frameoverride var frameOfPresentedViewInContainerView
//重写此方法可以在弹框即将显示时执行所需要的操作override func presentationTransitionWillBegin()
//重写此方法可以在弹框显示完毕时执行所需要的操作override func presentationTransitionDidEnd(_ completed: Bool)
//重写此方法可以在弹框即将消失时执行所需要的操作override func dismissalTransitionWillBegin()
//重写此方法可以在弹框消失之后执行所需要的操作override func dismissalTransitionDidEnd(_ completed: Bool)
重写初始化方法:
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { super.init(presentedViewController:presentedViewController,presenting: presentingViewController)}
在大多数时候,我们希望底部弹出框出现时,先前的显示区域能够灰暗一些,来强调弹出框的显示区域是用户当前操作的首要区域。因此,我们给这个自定义的类添加一个遮罩:
lazy var blackView: UIView = { let view = UIView() if let frame = self.containerView?.bounds { view.frame = frame } view.backgroundColor = UIColor.black.withAlphaComponent(0.5) return view}()
重写presentationTransitionWillBegin、dismissalTransitionWillBegin和dismissalTransitionDidEnd(_ completed: Bool)方法。在弹窗即将出现时把遮罩添加到containerView,并通过动画将遮罩的alpha设置为1;在弹窗即将消失时通过动画将遮罩的alpha设置为0;在弹框消失之后将遮罩从containerView上移除:
override func presentationTransitionWillBegin() { blackView.alpha = 0 containerView?.addSubview(blackLayerView) UIView.animate(withDuration: 0.5) { self.blackView.alpha = 1 }}
override func dismissalTransitionWillBegin() { UIView.animate(withDuration: 0.5) { self.blackView.alpha = 0 }}
override func dismissalTransitionDidEnd(_ completed: Bool) { if completed { blackView.removeFromSuperview() }}
接下来,我们重写frameOfPresentedViewInContainerView这个属性。它决定了弹出框在屏幕中的位置,由于我们是底部弹出框,我们设定一个弹出框的高度controllerHeight,即可得出弹出框的frame:
override var frameOfPresentedViewInContainerView: CGRect { return CGRect(x: 0, y: UIScreen.main.bounds.height-controllerHeight, width: UIScreen.main.bounds.width, height: controllerHeight)}
为了便于我们创建各种各样的底部弹出框,我们创建一个基类PresentBottomVC继承自UIViewController,并添加一个属性controllerHeight用于得到弹出框的高度:
public class PresentBottomVC: UIViewController { public var controllerHeight: CGFloat? { get { return self.controllerHeight } }}
之后,我们就可以新建继承自PresentBottomVC并重写controllerHeight属性的类来实现定制化底部弹出框。为了方便调用弹出方法,我们给UIViewController添加一个Extension,并实现UIViewControllerTransitioningDelegate协议:
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}
可以看到,所有继承自PresentBottomVC的ViewController都可以通过该方法来从另一个ViewController的底部弹出。例如,我们新建一个类FirstBottomVC,重写controllerHeight并设为200,在页面中添加一个关闭按钮:
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() { super.viewDidLoad() view.backgroundColor = .cyan view.addSubview(closeButton) } @objc func closeButtonClicked() { self.dismiss(animated: true, completion: nil) }}
之后在需要弹出的时候调用UIViewController的presentBottom(_ vc: PresentBottomVC.Type)方法就可以一句代码搞定啦:
self.presentBottom(FirstBottomVC.self)
效果如下图:
测试用的弹框写好了,我们只要根据自己的需求去创建不同的PresentBottomVC的子类就可以方便快捷的实现各种各样的底部弹出框啦。实例中的两个效果可以参考GitHub源码(https://github.com/IkeBanPC/PresentBottom)
作者:IsaacPan
链接:https://juejin.im/post/5a9651d25188257a5911f666
iOS开发整理发布,转载请联系作者授权
【点击成为Java大神】
相关文章推荐
- 【iOS学习】用UIPresentationController来写一个简洁漂亮的底部弹出控件
- 漂亮的弹出对话框,Asp.net的一个控件
- jquery封装了一个简洁轻巧的可拖动可自定义样式的纯div+css带遮罩层的仿模态弹出框
- Android中软键盘弹出时底部控件会上移的问题
- iOS键盘弹出的时候会挡住底部的控件,可以通过以下方法将整个UIView上移。
- 一个SDI程序基于CFormView视。上面放一个CStatic控件,给视图添加双击消息,运行程序后,双击视图,会有弹出消息响应。 但是双击CStatic类控件,却没有响应
- 一个WinForm记事本程序(包含主/下拉/弹出菜单/打开文件/保存文件/打印/页面设置/字体/颜色对话框/剪切版操作等等控件用法以及记事本菜单事件/按键事件的具体代码)
- 【分享】分享一个非常漂亮且好用的绘图控件QCustomPlot - qwt的完美替代品
- 页面从底部弹出一个popWindow
- Android而一个超级漂亮的日历控件
- 转 android 从底部弹出一个popuwindow,渐入渐出效果。我这里是用在购物车需要选择购买选项的操作。
- 新版博客更简洁和漂亮了,赞一个
- android 让一个控件按钮居于底部的几种方法
- 一个WinForm记事本程序(包含主/下拉/弹出菜单/打开文件/保存文件/打印/页面设置/字体/颜色对话框/剪切版操作等等控件用法以及记事本菜单事件/按键事件的具体代码)
- 封装一个Win32弹出提示框的函数(用于STATIC等控件显示Tooltip)
- 一个支持ListView的底部弹出控件 PopupWindow 小例子
- 分享一个漂亮的ProgressBar控件
- 弹出输入法时,不会把底部的控件顶到上边
- Android 控件——利用Dialog实现底部弹出对话框
- 一个简单的PopupWindow做的选项菜单点击按钮会在按钮下弹出几个下拉控件