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 ...
随机推荐
- C#获取本周五日期字符串
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using ...
- day22:初识面向对象
1,类可以理解为是一个模子,可以是代码精简,方便增加实例,方便修改,更加规范,能知道具体的属性,方法,但是不知道具体的值 2,对象有具体的值,属性和技能都是根据类规范的 3, 先有类才有对象 4,面向 ...
- 三报文握手 四报文握手 TCP运输连接管理
三报文握手 四报文握手 TCP运输连接管理
- 解决配置Windows Update失败问题
大家都清楚电脑总是需要更新一些补丁,不过,很多系统用户发现更新了补丁之后,开机会出现windows update更新失败的情况,提示“配置Windows Update失败,还原更改,请勿关闭计算机”信 ...
- 3、配置XShell上传文件
1.yum -y install lrzsz(安装 lrzsz) 2.rz -y(会弹出选择文件框,选择上传文件)
- 【Idea】-NO.162.Idea.1 -【Idea Unable to import maven project: See logs for details】
Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...
- 简单的C++输出日志
myLog.h #ifndef __myLog_H_ #define __myLog_H_ #include <stdio.h> #include <stdlib.h> #in ...
- js选中变色,不选中鼠标放上变色
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...
- 使用 dom4j 处理 xml (1)
解决问题需要,自己简单学习了一下dom4j 的基本用法: (1)读取 xml 文件: (2)修改 xml 文件. 需要的 jar 包: dom4j-xxx.jar (可以在 https://dom4j ...
- IT题库6-同步和异步
同步就是许多线程同时共用一个资源,一个线程在用别的线程就要等待.异步相反,可以不用等待. 同步:发送一个请求,等待返回,然后才能再发送下一个请求:异步:发送一个请求,不等待返回,随时可以再发送下一个请 ...