转载自 

UIPresentationController是提供高级视图切换的类。它让管理present ViewController的过程变得简单。

先讲一些presentation基础知识,在iPad的设置页面,可以通过popOver弹出一个UIViewController,这个弹出的,可以和用户交互的Controller叫做PresentedViewController,而后面那个被部分遮挡的UIViewController叫做PresentingViewController,而在UIPresentationController中,PresentedViewController是presentation的content,而PresentingViewController叫做Chrome。如下图:

kg9l1xv6wlvuxs18us31vzsjhztrtc2l.jpg!conPresentedViewController和PresentingViewController
0s89tcp3kin0memvexrxu14mc8mesrs4.jpg!conContent

2f6ofboq6xrq53drt9x1bjioy1hohob7.jpg!conChrome

所有的UIViewController的presentation都是由UIPresentationController管理的。在UIPresentationController中可以定义content和chrome的动画,可以根据大小的变化来改变content大小,可以根据系统的不同,来改变展示方式,UIPresentationController也是可复用的,可以很容易的拿到其他的UIViewController中去使用。


UIPopoverPresentationController

它在iOS8中替代了UIPopoverController,它在功能上与旧的controller完全等同,并且新增了一些内置的适配特性,可以自动适配iPad与iPhone。以下是新版与旧版接口的比较:

UIPopoverController使用方法:

ksaqncrcedk1xex8lnyizfqred5vl38y.jpg!con

我们先声明了一个UIViewController作为content controller,使用它初始化了一个UIPopoverController,然后调用presentPopover方法来展示它。这是在iPad上的用法。如果要创建一个在iPad与iPhone上通用的方法,那么需要以下的代码:

9swid9fqjxv7bfhp8nlnsbpu1w3oinwe.jpg!con

我们需要去判断设备是否为iPad,若为iPad,那么创建一个UIPopoverController并展示它,若不是iPad,那么就需要调用常规的presentViewController方法来展示一个UIViewController。

然而我们如果使用UIPopoverPresentationController,那么就不再需要判断设备:

9wgy2x4zoco69xxjip63f9phwsna7c2a.jpg!con

将UIViewController的modalPresentationStyle设置成UIModalPresentationPopover,这个值用来实现popover效果,并且各个平台自动适应。第二行中,通过popoverPresentationController属性来获取它的popoverPresentationController,而不是创建一个新的。然后设置它的一些界面属性,最后调用presentViewController方法来显示这个controller。这样就可以在iPad与iPhone显示自动适应的popover效果了,如下图所示:

te1ldmz98r87a5ls738em9ek4ivt6m2t.jpg!coniPad效果
lup9xat6n6kotahlwy8f408c6ibdgu0h.jpg!coniPhone效果

可见,iPhone上,只是作为一个普通的UITableViewController展示出来。

iPhone上的自适应是在delegate中实现的:

4dgelqslcyffqonh9sfmg99nx529rqoh.jpg!con

在第一个方法中,指定了UIModelPresentationFullScreen的样式来展示controller。第二个方法中,我们将presentedViewController使用UINavigationController包装起来,使得可以在选中某项之后,通过navigationController提供的一些方法来展示内容,或者后退。


UIAlertView与UIActionSheet

UIAlertView与UIActionSheet都是继承自UIView的,但是它们在实现时,却用了一些UIViewController的方式,并且它的接口比较旧,采用的是delegate方式。在iOS8中,新增了UIAlertController,它可以同时实现Alert和Action Sheets,并且接口采用block方式,它将在应用的同一个window中展示,而不是之前的新window中展示,它还具有和之前的popover controller相同的实现方式,通过presentViewController来展示。下面是新的UIAlertController的用法:

4w239e39fuqyswrhac91ga3oqje73gyu.jpg!con

首先创建一个UIAlertController,之后通过addAction方法来增加一些action,而UIAlertAction使用block来设置按钮的点击处理方法。最后,通过调用presentViewController来展示UIAlertController。


UISearchDisplayController

search在iOS中包含两部分:UISearchBar与UISearchDisplayController。它们都是很古老的接口,功能与样式都不能满足现状的应用,UISearchDisplayController的配置项很少,它只能在tableView中显示结果,而不能在collectionView或者mapView中显示。它的present过程只是通过addSubview来将view作为一个子view添加上去。而如果它的父view是一个scrollView,那么手势处理就会有冲突。在iOS8中,引入了UISearchController,它允许presentingController是任意类型的,不一定是全屏幕的,search bar animation可以自定义,并且可以在不同平台上适配。

在之前的接口中,我们使用UISearchDisplayController来实现search功能:

iupewlq8zsqlea0rqd2c6vyu6wamc1y0.jpg!con

首先初始化一个UISearchBar,再用它初始化一个UISearchDisplayController,指定controller的searchResuleDataSource与searchResultDelegate,之后,将searchBar作为当前view中的tableView的tableHeaderView来显示。而在iOS8中,实现方式是这样的:

4ksoemoztyhvkio7mo8esr6y95lz3cbm.jpg!con

首先初始化一个自定义的resultsController,可以是一个collectionView,也可以是一些其他的自定义样式。之后使用这个resultsController创建一个UISearchController,指定searchController的searchResultsUpdater为resultsController,之后将searchBar加到tableView的tableHeaderView上,最后,设置当前Controller的definesPresentationContext为YES,表示UISearchController在present时,可以覆盖当前controller。


经过这样的修改,所有的都变成了Controller,不再有UIView组件,也不再需要通过创建新window来展示UIView,更加容易控制。UIPresentationController为Content与Chrome提供了一个很好的抽象,并且在iPad与iPhone间,自动适应使得编码更简洁。