UIKit将视图控制器的内容与内容在屏幕上显示和呈现的方式分离。 呈现的视图控制器由底层呈现控制器对象管理,其管理用于呈现视图控制器的视图的视觉样式。 呈现控制器可以执行以下操作:
- 设置提供的视图控制器的大小。
- 添加自定义视图以更改所显示内容的视觉外观。
- 为任何它的自定义视图提供过渡动画。
- 在应用程序环境中发生更改时调整呈现视图的视觉外观。
UIKit提供了标准呈现方式的呈现控制器。 当您将视图控制器的呈现样式设置为UIModalPresentationCustom并提供适当的转换委托时,UIKit将使用您的自定义呈现控制器。
自定义呈现过程
当您呈现其呈现样式为UIModalPresentationCustom的视图控制器时,UIKit会查找自定义的显示控制器来管理呈现过程。 随着呈现的进行,UIKit调用呈现控制器的方法,让它有机会设置任何自定义视图并将它们动画化到位置。
呈现控制器与任何动画对象一起工作,以实现整体转换。 该动画对象将视图控制器的内容动画化到屏幕上,并且呈现控制器处理一切。 通常,你的呈现控制器会自动生成自己的视图,但您也可以覆盖呈现控制器的presentView方法,该动画对象对所有或部分视图进行动画处理。
在呈现期间,UIKit:
调用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:转换委托的方法来检索您的自定义呈现控制器
询问动画和交互式动画对象的转换委托(如果有的话)
调用呈现控制器的presentationTransitionWillBegin方法您的此方法的实现应将任何自定义视图添加到视图层次结构并配置这些视图的动画。
从呈现控制器获取presentView此方法返回的视图由动画对象动画定位。 通常,此方法返回所呈现的视图控制器的根视图。 你的呈现控制器可以根据需要使用自定义背景视图替换该视图。 如果你指定了其他视图,则必须将提供的视图控制器的根视图嵌入到视图层次结构中。
执行转换动画
过渡动画包括由动画师对象创建的主要动画,以及你配置为与主要动画并行运行的任何动画。 在动画过程中,UIKit调用演示控制器的containerViewWillLayoutSubviews和containerViewDidLayoutSubviews方法,以便您可以根据需要调整自定义视图的布局。转换动画完成时调用presentationTransitionDidEnd:方法
在关闭期间,UIKit:
- 从当前可见的视图控制器获取您的自定义呈现控制器
- 询问动画和交互式动画对象的转换委托(如果有的话)
- 调用呈现控制器的dismissalTransitionWillBegin方法
你的方法的实现应将任何自定义视图添加到视图层次结构并配置这些视图的动画。 - 从呈现控制器获取已经呈现的视图
- 执行转换动画
过渡动画包括由动画师对象创建的主要动画,以及你配置为与主要动画并行运行的任何动画。 在动画过程中,UIKit调用呈现控制器的containerViewWillLayoutSubviews和containerViewDidLayoutSubviews方法,以便您可以删除任何自定义约束。 - 转换动画完成时调用dismissalTransitionDidEnd:方法
在呈现过程中,你的呈现控制器的frameOfPresentedViewInContainerView和presentedView方法可能会被调用多次,因此您的实现应该很快返回。 此外,您的presentView方法的实现不应该尝试设置视图层次结构。 视图层次结构应该在调用方法时进行配置。
创建自定义呈现控制器
要实现自定义呈现风格,请将UIPresentationController子类化并添加代码以创建呈现控制器的视图和动画。 创建自定义呈现控制器时,请考虑以下问题:
- 你要添加哪些视图?
- 如何在屏幕上为任何其他视图设置动画?
- 应该是什么大小的呈现视图控制器?
- 应该如何在水平规则和水平紧凑的尺寸类之间进行调整?
- 呈现完成后,应该删除呈现视图控制器的视图吗?
所有这些决定都需要覆盖UIPresentationController类的不同方法。
设置呈现的视图控制器的Frame
你可以修改呈现的视图控制器的框架矩形,以便它只填充部分可用空间。 默认情况下,呈现的视图控制器的大小设置为完全填充容器视图的框架。 要更改框架矩形,重写呈现控制器的frameOfPresentedViewInContainerView方法。 代码清单11-1显示了一个示例,其中框架更改为仅覆盖容器视图的右半部分。 在这种情况下,呈现控制器使用背景调暗视图来覆盖容器的另一半。
代码清单11-1更改所呈现视图控制器的frame
- (CGRect)frameOfPresentedViewInContainerView {
CGRect presentedViewFrame = CGRectZero;
CGRect containerBounds = [[self containerView] bounds];
presentedViewFrame.size = CGSizeMake(floorf(containerBounds.size.width / 2.0),
containerBounds.size.height);
presentedViewFrame.origin.x = containerBounds.size.width -
presentedViewFrame.size.width;
return presentedViewFrame;
}
管理和动画自定义视图
自定义呈现通常涉及向所呈现的内容添加自定义视图。 使用自定义视图来实现纯视觉装饰,或使用它们向呈现控制器添加实用行为。 例如,背景视图可以包括姿势识别器以跟踪所呈现内容的界限之外的特定动作。
呈现控制器负责创建和管理与其呈现相关联的所有自定义视图。 通常,您在呈现控制器的初始化期间创建自定义视图。 代码清单11-2显示了创建自己的调光视图的自定义视图控制器的初始化方法。 此方法创建视图并执行一些最小配置。
代码清单11-2初始化表示控制器
- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController
presentingViewController:(UIViewController *)presentingViewController {
self = [super initWithPresentedViewController:presentedViewController
presentingViewController:presentingViewController];
if(self) {
// Create the dimming view and set its initial appearance.
self.dimmingView = [[UIView alloc] init];
[self.dimmingView setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.4]];
[self.dimmingView setAlpha:0.0];
}
return self;
}
您使用presentationTransitionWillBegin方法在屏幕上动画自定义视图。 在此方法中,配置自定义视图,并将它们添加到容器视图中,如代码清单11-3所示。 使用呈现或呈现视图控制器的转换协调器来创建任何动画。 在此方法中不要修改呈现的视图控制器的视图。 animator对象负责将呈现的视图控制器动画化到从frameOfPresentedViewInContainerView方法返回的框架矩形中。
代码清单11-3将调光视图动画化到屏幕上
- (void)presentationTransitionWillBegin {
// Get critical information about the presentation.
UIView* containerView = [self containerView];
UIViewController* presentedViewController = [self presentedViewController];
// Set the dimming view to the size of the container's
// bounds, and make it transparent initially.
[[self dimmingView] setFrame:[containerView bounds]];
[[self dimmingView] setAlpha:0.0];
// Insert the dimming view below everything else.
[containerView insertSubview:[self dimmingView] atIndex:0];
// Set up the animations for fading in the dimming view.
if([presentedViewController transitionCoordinator]) {
[[presentedViewController transitionCoordinator]
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>
context) {
// Fade in the dimming view.
[[self dimmingView] setAlpha:1.0];
} completion:nil];
}
else {
[[self dimmingView] setAlpha:1.0];
}
}
在呈现控制器结束时,使用presentationTransitionDidEnd:方法处理由呈现控制器取消引起的任何清除操作。 如果不满足条件,交互式动画对象可能会取消转换。 当这种情况发生时,UIKit调用presentationTransitionDidEnd:方法,值为NO。 取消操作时,删除在演示开始时添加的任何自定义视图,并将任何其他视图返回到之前的配置,如代码清单11-4所示。
- (void)presentationTransitionDidEnd:(BOOL)completed {
// If the presentation was canceled, remove the dimming view.
if (!completed)
[self.dimmingView removeFromSuperview];
}
当视图控制器被关闭时,使用dismissalTransitionDidEnd:方法从视图层次结构中删除自定义视图。 如果你想动画你的视图的消失,在dismissalTransitionDidEnd:方法中设置这些动画。 代码清单11-5显示了用于删除前面示例中的调光视图的两种方法的实现。 始终检查dismissalTransitionDidEnd:方法的参数,以查看解除是成功还是已取消。
代码清单11-5取消呈现控制器的视图
- (void)dismissalTransitionWillBegin {
// Fade the dimming view back out.
if([[self presentedViewController] transitionCoordinator]) {
[[[self presentedViewController] transitionCoordinator]
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>
context) {
[[self dimmingView] setAlpha:0.0];
} completion:nil];
}
else {
[[self dimmingView] setAlpha:0.0];
}
}
- (void)dismissalTransitionDidEnd:(BOOL)completed {
// If the dismissal was successful, remove the dimming view.
if (completed)
[self.dimmingView removeFromSuperview];
}
将您的呈现控制器控制权自动给UIKit
呈现视图控制器时,请执行以下操作,使用自定义演示控制器显示它:
- 将提供的视图控制器的modalPresentationStyle属性设置为UIModalPresentationCustom。
- 将转换委托分配给所呈现的视图控制器的transitioningDelegate属性。
- 实现presentationControllerForPresentedViewController:presentingViewController:sourceViewController:转换委托的方法。
UIKit调用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:当您需要呈现控制器时,您的转换委托的方法。 这个方法的实现应该和代码清单11-6中的一样简单。 只需创建呈现控制器,配置它,并返回它。 如果从此方法返回nil,UIKit使用全屏呈现样式呈现视图控制器。
代码清单11-6创建自定义呈现控制器
- (UIPresentationController *)presentationControllerForPresentedViewController:
(UIViewController *)presented
presentingViewController:(UIViewController *)presenting
sourceViewController:(UIViewController *)source {
MyPresentationController* myPresentation = [[MyPresentationController]
initWithPresentedViewController:presented presentingViewController:presenting];
return myPresentation;
}
适应不同大小类
当呈现在屏幕上时,UIKit通知您的呈现控制器基础特征或容器视图的大小发生变化。 这种变化通常在设备旋转期间发生,但可以在其他时间发生。 您可以使用特征和大小通知来调整呈现控制器的自定义视图,并根据需要更新呈现控制器样式。