UIPresentationController - iOS自定义模态弹出框
参考:
首先说下需求,就是一个自定义的模态弹出框,这种需求应该很广

对于弹出框,我们首先想到的就是UIAlertController这个类。但是这个类只能创建两种类型的弹出框,actionSheet和alert。要想使用这个类实现上面的效果,很难,之前为了实现这个效果在网上找来找去,最后使用了View叠加View的方式,也就是一个大的View当做背景,中间的控件使用一个View来实现。这种方法有个缺点,就是当显示后,导航栏的按钮,比如返回按钮还是可以点击的,也就是整个View并不能覆盖真个屏幕,实现真正的模态。而且使用View看起来效果也不好。
那么下面就来说说怎么实现上面图中的效果,真正的模态弹出框。
要实现上面的效果,首先我们需要一个ViewController来实现要弹出的框,也就是上图中的时间选择部分,那么谁来控制这个ViewController的显示呢?我们就需要下面一个类
有一个类是必不可少的:UIPresentationController,这个类看起来很陌生。我们知道从一个ViewController跳转到另一个,有两种方式:
1)经常使用的是push的方式,控制器从屏幕的右边弹出来,显示的控制器带有返回按钮
2) 还有一种方式就是present,这种方式可能不经常使用,默认的效果是从屏幕底部弹出来的,并占满整个屏幕,没有返回按钮
上面的时间选择弹出框就是通过第二种方式实现的,在我们调用present的时候,系统会提供一个默认的UIPresentationController,但是UIKit默认的实现不能满足我们的需求,但是这个类是可以自定义的,用来控制present的方式。
那个这个UIPresentationController可以用来干什么呢?有以下四个功能:
1) 设置弹出框的大小,上图中也就是中间时间选择框的大小
2) 添加视图来改变展示内容的外观
3) 支持自定义视图的转场动画
4) 适配展示的外观当App环境改变时,比如屏幕旋转
那么UIKit怎么才会使用我们自定义的UIPresentationController呢?需要以下两个条件:
1)当你present一个控制器的时候,设置其modalPresentationStyle为custom,也就是指定present的类型为自定义的,不使用系统的
2)添加一个UIViewControllerTransitionDelegate代理,这个代理用来获取自定义的UIPresentationController
实现模态框的处理流程:
1)当present的时候,UIKit将会调用transitioning代理方法
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController?
来获取我们自定义的UIPresentationController
2) 请求 transitioning 代理获取动画和交互动画对象,如果存在
3) 调用自定义 UIPresentationController 的 presentationTransitionWillBegin 方法,这个方法的实现应该是添加自定义的视图到视图层级中和为这些视图配置动画
4) 从自定义的 UIPresentationController 中获取 presentedView
这个视图被动画对象操作并安放到指定的位置。通常 presentedView 返回的是要 present 的视图控制器的根视图。如果有需要,我们的 presentationController 可以使用一个背景视图替换到这个根视图。
如果你指定一个不同的视图,你必须把 presented 的视图控制器的根视图嵌入到视图层级中。
5) 执行转场动画
转场动画包含主要的一个,由动画对象创建。还有任意你配置的动画,伴随主要动画。
在动画的处理过程中,UIKit将会调用 containerViewWillLayoutSubviews 和 containerViewDidLayoutSubviews,在这两个方法中,你可以根据你的需要调整自定义视图。
6) 最后当转场动画结束的时候调用 presentationTranistionDidEnd
以上就是 present 过程中所做的处理
模态框 dismiss 的处理流程
1) 从当前可见的视图控制器获取自定义的UIPresentationController
2) 请求 transitioning 代理获取动画和交互动画对象,如果存在
3) 调用 presentationController 的 dismissalTransitionWillBegin
这个方法的实现可以添加自定义视图及动画。
4) 获取已经存在的 presentedView
5) 执行转场动画
转场动画包含了主要的一个,由动画对象创建。还有任意你配置的动画,伴随主要动画。
在动画处理的过程中,UIKit调用 containerViewWillLayoutSubviews 和 containerViewDidLayoutSubviews,在这两个方法中,你可以删除任何自定义的约束。
6) 最后当转场动画结束时调用 dismissalTransitionDidEnd
注意:在 present 的过程中 frameOfPresentedViewInContainerView 和 presentedView 将会调用数次,所以这两个方法的实现必须要简单,快速返回。而且,presentedView 的实现不应该设置视图层级,在调用 presentedView 的时候,视图层级应该已经设置好了。
下面就来看看怎么自定义UIPresentationController?怎么使用?
创建一个自定义的Presentation Controller
为了实现自定义的 presentation style,你需要从 UIPresentationController 继承编写代码实现自定义的视图和动画效果。
设置被 presented 的视图控制器的 frame
你可以修改 presented 控制器的 frame 来实现只占用可用空间的部分空间。presented 控制器默认占用整个 container 视图。为了改变这个 frame 占用的空间,可以重写 presentation 控制器的 frameOfPresentedViewInContainerView。代码可以如下:
override var frameOfPresentedViewInContainerView: CGRect {
let containerBounds = self.containerView?.bounds
let presentedViewFrame = CGRect.init(x: (containerBounds?.size.width)! / 2.0 - , y: (containerBounds?.size.height)! / - , width: 300.0, height: 330.0)
return presentedViewFrame
}
管理和呈现自定义视图的动画
自定义的 presentation 经常涉及添加自定义的视图到要 presented 的内容中。使用自定义的视图可以显示纯粹的视觉上的装饰或者添加实际上行为到 presentation 上。比如你想在 presented 内容的外部添加手势。
自定义的 presentation controller 负责所有和 presentation 关联的自定义的视图的创建和管理。一般创建视图的操作在初始化方法中编写:
var dimmingView: UIView?
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
self.dimmingView = UIView.init()
self.dimmingView?.backgroundColor = UIColor.white.withAlphaComponent(0.5)
self.dimmingView?.alpha = 0.0
}
你给你的视图在显示到屏幕上的时候添加动画,在方法 presentationTransitionWillBegin 中实现。如下:
override func presentationTransitionWillBegin() {
let containerView = self.containerView
// 设置背景透明度
// containerView?.backgroundColor = UIColor.lightGray.withAlphaComponent(0.6)
let presentedViewController = self.presentedViewController
self.dimmingView?.frame = (containerView?.bounds)!
self.dimmingView?.alpha = 0.0
containerView?.insertSubview(self.dimmingView!, at: )
if (presentedViewController.transitionCoordinator != nil) {
presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
self.dimmingView?.alpha = 1.0
}, completion: nil)
} else {
self.dimmingView?.alpha = 1.0
}
}
在 presentation 的最后阶段,我们可以在 presentationTransitionDidEnd 中实现由于 presentation 被取消引起的清理工作。一个交互式的动画对象可能取消转场如果它的临界条件不符合的话。当这种情况发生的时候,UIkit 将会调用 presentationTransitionDidEnd。当一个取消发生的时候,我们需要移除之前添加的视图和恢复任何其它视图的配置。
override func presentationTransitionDidEnd(_ completed: Bool) {
if !completed {
self.dimmingView!.removeFromSuperview()
}
}
当我们 dismiss 视图控制器的时候会调用 dismissalTransitionWillBegin 以及 dismissalTransitionDidEnd,如果你想要使用动画让你的视图消失,可以在 dismissalTransitionWillBegin 配置,以及在 dismissalTransitionDidEnd 移除自定义的视图,如下:
override func dismissalTransitionWillBegin() {
if self.presentedViewController.transitionCoordinator != nil {
self.presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
self.dimmingView?.alpha = 0.0
}, completion: nil)
} else {
self.dimmingView?.alpha = 0.0
}
}
override func dismissalTransitionDidEnd(_ completed: Bool) {
if completed {
self.dimmingView?.removeFromSuperview()
}
}
至此,整个过程都实现了,如果是不需要背景半透明状态,可以不用添加自定义的视图。里面有一些地方还是不很理解,由于很少使用动画,所以没有实现更加高级的动画操作,里面的 transitionCoordinator 也没做研究,以后用到再说。总的来说一个模态弹出框已经可以使用了。还请多多指教。
实例地址:https://github.com/huangzhengguo/iOSSamples/tree/master/SwiftTools/SwiftTools/Tools/ModalController
UIPresentationController - iOS自定义模态弹出框的更多相关文章
- iOS自定义提示弹出框(类似UIAlertView)
菜鸟一枚,大神勿喷.自己在牛刀小试的时候,发现系统的UIAlertView有点不喜欢,然后就自己自定义了一个UIAlertView,基本上实现了系统的UIAlertView,可以根据项目的需求修改UI ...
- Bootstrap模态弹出框
前面的话 在 Bootstrap 框架中把模态弹出框统一称为 Modal.这种弹出框效果在大多数 Web 网站的交互中都可见.比如点击一个按钮弹出一个框,弹出的框可能是一段文件描述,也可能带有按钮操作 ...
- iOS:模态弹出窗控制器UIPopoverPresentationController
模态弹出窗控制器:UIPopoverPresentationController 实质:就是将内容控制器包装成PopoverPresentationController的形式,然后再模态出来,必须指定 ...
- 玩转Bootstrap(JS插件篇)-第1章 模态弹出框 :1-4 模态弹出框--结构分析
模态弹出框--结构分析 Bootstrap框架中的模态弹出框,分别运用了“modal”.“modal-dialog”和“modal-content”样式,而弹出窗真正的内容都放置在“modal-con ...
- 玩转Bootstrap(JS插件篇)-第1章 模态弹出框 :1-3 模态弹出框
模态弹出框(Modals) 这一小节我们先来讲解一个“模态弹出框”,插件的源文件:modal.js. 右侧代码编辑器(30行)就是单独引入 bootstrap 中发布出的“modal.js”文件. 样 ...
- bootstrap中的modal 模态弹出框不能放在 form_for里面,一弹出modal会自动submit掉form
bootstrap中的modal 模态弹出框不能放在 form_for里面,一弹出modal会自动submit掉form
- 清除ios系统alert弹出框的域名
清除ios系统alert弹出框的域名 <script> window.alert = function(name) { var iframe = document.createElemen ...
- 控制非模态弹出框(showModelessDialog)唯一且随父页面关闭
网站开发中,常常会遇到需要弹出窗体的情况,一般弹出框有模态和非模态两种,如下: 模态:window.showModalDialog() 非模态:window.showModelessDialog() ...
- 自定义PopupWindow弹出框(带有动画)
使用PopupWindow来实现弹出框,并且带有动画效果 首先自定义PopupWindow public class LostPopupWindow extends PopupWindow { pub ...
随机推荐
- 关于Mysql6.0+的时区错乱问题
如果使用mysql6.0+的JDBC驱动版本的时候,有时候会出现程序时间与数据库时间相差很多个小时; 1.如果以北京时间为例,相差8个小时的情况一般是你在连接jdbc的url中没有标明system_t ...
- Easyui datagrid 数据表格 表格列头右键菜单选择展示列 JS
Easyui ,数据表格加载出来以后,在表格头右键,会有显示筛选的功能: 如图: 然后可以取消勾选,就变成下面这个样子: 功能的实现是通过重写了easyui 的 $.fn.datagrid.defau ...
- hydra用法
三.Syntax # hydra [[[-l LOGIN|-L FILE] [-p PASS|-P FILE]] | [-C FILE]] [-e ns] [-o FILE] [-t TASKS] [ ...
- jquery和js 判断下拉框选项选中值
js <script> var selectId = document.getElementById("VariantType");//获取ID selectId.on ...
- C与C++相互调用
C++编译器可以兼容并编译C语言,但优先使用C++编译方式,extern关键字让C++编译器使用C语言编译方式编译. extern "C" { // c 编译器编译的代码 } C+ ...
- 4.hadoop的安装与配置
1.下载hadoop-2.6.2.tar.gz. 2.复制hadoop-2.6.2.tar.gz到/usr/local/目录下. 3解压 #tar -zxvf hadoop-2.6.2.tar.g ...
- 红黑树与AVL特性
红黑树:比较平衡的二叉树,没有一条路径会比其他路径长2倍,因而是近似平衡的.所以相对于严格要求平衡的AVL树来说,它的旋转保持平衡次数较少.插入删除次数多的情况下我们就用红黑树来取代AVL. 红黑树规 ...
- Install Superset from Python3.6
本文安装Superset大致分为以下部分: 在操作系统中安装相关依赖,我所用的操作系统为Centos6.5 安装Python3.6.6 安装Superset 详细步骤如下: 相关依赖的安装 yum i ...
- 使用springmvc进行文件的上传和下载
文件的上传 SpringMVC支持文件上传组件,commons-fileupload,commons-fileupload依赖commons-io组件 配置步骤说明 第一步:导入包 commons-f ...
- js 获取url具体参数
用JS获取地址栏参数的方法(超级简单) 方法一:采用正则表达式获取地址栏参数:( 强烈推荐,既实用又方便!) function GetQueryString(name) { var reg = new ...