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 ...
随机推荐
- Autofac之生命周期和事件
Autofac为注册的类型对象提供了一套生命周期事件,覆盖了一个类型从注册到最后“释放”的一套事件.有了这些事件,我们可以相对方便的在类型对象的各个阶段进行AOP操作. builder.Registe ...
- html实现调用jar包
整体思路:html引用URL protocol-本地注册表key,key对应某一c#写的exe可执行文件,由exe可执行文件调用cmd,cmd执行jar包. 1.添加注册表: Windows Regi ...
- asp.net core 使用NLog记录日志到txt文件
一.使用VisualStudioCode创建一个webapi项目(也可以是mvc等).一个类库(用于封装记录日志方法,当然如果使用依赖注入到控制台项目,就不需要此类库了). 二.在类库中添加NLog. ...
- OSPF(Open Shortest Path First)
1.概述 路由协议OSPF全称为Open Shortest Path First,也就开放的最短路径优先协议,因为OSPF是由IETF开发的,所以所有厂商都可以用. OSPF的流量使用IP协议号. O ...
- 接口测试工具-Jmeter使用笔记(八:模拟OAuth2.0协议简化模式的请求)
背景 博主的主要工作是测试API,目前已经用Jmeter+Jenkins实现了项目中的接口自动化测试流程.但是马上要接手的项目,API应用的是OAuth2.0协议授权,并且采用的是简化模式(impli ...
- 3.2.2 SpringMVC配置式开发
SpringMVC配置式开发 1. SpringMVC运行原理(执行过程) 2. 需求 用户提交一个请求, 服务端处理器接收到请求后, 给出一条信息,在相应页面中显示该条信息 3. 开发步骤 (1) ...
- IR2104s半桥驱动使用经验
多次使用IR2104s,每次的调试都有种让人吐血的冲动.现在将使用过程遇到的错误给大家分享一下,方便大家找到思路. 一.自举电容部分(关键) 1.听说自举电路必须要安装场效应管,于是我在使用过程中,安 ...
- leetcode143. Reorder List
用快慢双指针,可以使慢指针到达中间的时候快指针到达最后一个元素(奇数),或者倒数第二个元素(偶数).慢指针后面的元素是后半个链表,把后半个链表进行reverse,然后再插在原来的链表中就可以了 /** ...
- LeetCode-7-反转整数-c# 版本
c# 版本 // 给定一个 32 位有符号整数,将整数中的数字进行反转. public class Solution { public int Reverse(int x) { / // 边界判断 / ...
- 20.C# 创建自己的泛型类型
1.定义泛型类 可以使用以下语法创建泛型类,T可以是任意符合C#标识符命名规范的任意标识符 class MyGenericClass<T> { //.... } 泛型类可以包含任意多个类型 ...