ViewController编程指南展示和过渡-创建自定义呈现

UIKit将视图控制器的内容与内容在屏幕上显示和呈现的方式分离。 呈现的视图控制器由底层呈现控制器对象管理,其管理用于呈现视图控制器的视图的视觉样式。 呈现控制器可以执行以下操作:

  • 设置提供的视图控制器的大小。
  • 添加自定义视图以更改所显示内容的视觉外观。
  • 为任何它的自定义视图提供过渡动画。
  • 在应用程序环境中发生更改时调整呈现视图的视觉外观。

UIKit提供了标准呈现方式的呈现控制器。 当您将视图控制器的呈现样式设置为UIModalPresentationCustom并提供适当的转换委托时,UIKit将使用您的自定义呈现控制器。

自定义呈现过程

当您呈现其呈现样式为UIModalPresentationCustom的视图控制器时,UIKit会查找自定义的显示控制器来管理呈现过程。 随着呈现的进行,UIKit调用呈现控制器的方法,让它有机会设置任何自定义视图并将它们动画化到位置。

呈现控制器与任何动画对象一起工作,以实现整体转换。 该动画对象将视图控制器的内容动画化到屏幕上,并且呈现控制器处理一切。 通常,你的呈现控制器会自动生成自己的视图,但您也可以覆盖呈现控制器的presentView方法,该动画对象对所有或部分视图进行动画处理。

在呈现期间,UIKit:

  1. 调用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:转换委托的方法来检索您的自定义呈现控制器

  2. 询问动画和交互式动画对象的转换委托(如果有的话)

  3. 调用呈现控制器的presentationTransitionWillBegin方法您的此方法的实现应将任何自定义视图添加到视图层次结构并配置这些视图的动画。

  4. 从呈现控制器获取presentView此方法返回的视图由动画对象动画定位。 通常,此方法返回所呈现的视图控制器的根视图。 你的呈现控制器可以根据需要使用自定义背景视图替换该视图。 如果你指定了其他视图,则必须将提供的视图控制器的根视图嵌入到视图层次结构中。

  5. 执行转换动画
    过渡动画包括由动画师对象创建的主要动画,以及你配置为与主要动画并行运行的任何动画。 在动画过程中,UIKit调用演示控制器的containerViewWillLayoutSubviews和containerViewDidLayoutSubviews方法,以便您可以根据需要调整自定义视图的布局。

  6. 转换动画完成时调用presentationTransitionDidEnd:方法

在关闭期间,UIKit:

  1. 从当前可见的视图控制器获取您的自定义呈现控制器
  2. 询问动画和交互式动画对象的转换委托(如果有的话)
  3. 调用呈现控制器的dismissalTransitionWillBegin方法
    你的方法的实现应将任何自定义视图添加到视图层次结构并配置这些视图的动画。
  4. 从呈现控制器获取已经呈现的视图
  5. 执行转换动画
    过渡动画包括由动画师对象创建的主要动画,以及你配置为与主要动画并行运行的任何动画。 在动画过程中,UIKit调用呈现控制器的containerViewWillLayoutSubviews和containerViewDidLayoutSubviews方法,以便您可以删除任何自定义约束。
  6. 转换动画完成时调用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通知您的呈现控制器基础特征或容器视图的大小发生变化。 这种变化通常在设备旋转期间发生,但可以在其他时间发生。 您可以使用特征和大小通知来调整呈现控制器的自定义视图,并根据需要更新呈现控制器样式。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容