iOS review系列之Creating Custom Presentations

iOS review系列之使用Segues
iOS review系列之自定义转场动画
iOS review系列之Presenting a View Controller
iOS review系列之UIViewController

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

  • 设置 presented控制器的大小。
  • 添加自定义视图来更改presented内容的视觉外观。
  • 为它的任何自定义视图提供转场动画。
  • 当app的环境发生变化时,调整presentation的视觉外观。

UIKit为标准presentation样式提供了presentation控制器。当你将视图控制器的presentation样式设置为UIModalPresentationCustom并提供一个适当的转场代理时,UIKit会使用你的自定义presentation控制器。

自定义presentation过程

当你present一个视图控制器,它的presentation风格是UIModalPresentationCustom, UIKit寻找一个自定义的presentation控制器来管理presentation过程。随着presentation的进展,UIKit调用presentation控制器的方法,让它有机会设置任何自定义视图并使它们动起来。

presentation控制器与任何animator对象一起工作来实现整个转场。animator对象将视图控制器的内容动画到屏幕上,而presentation controller处理所有其他事情。通常,您的presentation控制器会使它自己的视图具有动画效果,但是您也可以重写presentation控制器的presentedView方法,并让animator对象使所有或部分视图具有动画效果。

在一次presentation中,UIKit:

  1. 调用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:的转场方法来检索您的自定义presentation控制器

  2. 询问Animator和交互式Animator对象的转场代理(如果有的话)

  3. 调用presentation controller的presentationTransitionWillBegin方法,此方法的实现应该将任何自定义视图添加到视图层次结构中,并为这些视图配置动画。

  4. 从presentation控制器获取presentedView

    此方法返回的视图由animator对象动画到指定位置。通常,这个方法返回被呈现的presented视图控制器的根视图。您的presentation控制器可以根据需要用自定义背景视图替换该视图。如果你指定了一个不同的视图,你必须将当前视图控制器的根视图嵌入到你的视图层次结构中。

  5. 执行转场动画

    转场动画包括animator对象创建的主动画和配置为与主动画一起运行的任何动画。有关转场动画的信息,请参阅转场动画序列。

    在动画过程中,UIKit调用你的presentation控制器的containerViewWillLayoutSubviewscontainerViewDidLayoutSubviews方法,这样你可以根据需要调整你自定义视图的布局。

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

在dismissal期间,UIKit:

  1. 从当前可见的视图控制器获取自定义presentation控制器

  2. 询问Animator和交互式Animator对象的转场代理(如果有的话)

  3. 调用presentation controller的dismissalTransitionWillBegin方法

    此方法的实现应该将任何自定义视图添加到视图层次结构中,并为这些视图配置动画。

  4. 从presentation控制器获取 presentedView

  5. 执行转场动画

    转场动画包括Animator对象创建的主动画和配置为与主动画一起运行的任何动画。有关转场动画的信息,请参阅转场动画序列。

    在动画过程中,UIKit调用你的presentation控制器的containerViewWillLayoutSubviewscontainerViewDidLayoutSubviews方法,这样你可以根据需要调整你自定义视图的布局

  6. 在转场动画完成时调用dismissalTransitionDidEnd:方法

在presentation过程中,您的presentation控制器的frameOfPresentedViewInContainerViewpresentedView方法可能会被调用多次,因此您的实现应该快速返回。另外,presentedView方法的实现不应该尝试设置视图层次结构。在调用方法时,视图层次结构应该已经配置好了。

Creating a Custom Presentation Controller

要实现自定义presentation样式,可以子类化UIPresentationController并添加代码来创建演示的视图和动画。在创建自定义presentation控制器时,请考虑以下问题:

  • 您想添加什么视图?

  • 如何在屏幕上设置其他视图的动画?

  • presented视图控制器应该是多大?

  • presentation如何在水平规则类和水平紧凑类屏幕之间进行调整?

  • 是否应该在presentation结束时移除呈现视图控制器的视图?

所有这些决策都需要重写UIPresentationController类的不同方法。

设置Presented视图控制器的Frame

您可以修改Presented视图控制器的 frame rectangle,使其只填充部分可用空间。默认情况下,Presented视图控制器的大小完全填充容器视图的Frame。要更改 frame rectangle,请重写Presented控制器的frameOfPresentedViewInContainerView方法。清单11-1显示了一个示例,其中frame被更改为只覆盖容器视图的右半部分。在本例中,Presented控制器使用background dimming view来重写容器的另一半。

- (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;
}

Managing and Animating Custom Views

自定义presentation通常涉及到向presented内容中添加自定义视图。使用自定义视图实现纯粹的视觉装饰,或使用它们向presentation添加实际行为。例如,背景视图可以合并手势识别器来跟踪presented内容范围之外的特定操作。

presentation控制器负责创建和管理与其表示相关联的所有自定义视图。通常,在presentation控制器初始化期间创建自定义视图。清单11-2显示了自定义视图控制器的初始化方法,它创建了自己的 dimming view。此方法创建视图并执行一些最小配置。

- (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方法将自定义视图动画到屏幕上。在此方法中,配置自定义视图并将其添加到容器视图,如下代码所示。使用presented视图控制器或presenting视图控制器的转场协调器来创建任何动画。不要在这个方法中修改当前视图控制器的视图。animator对象负责将presented视图控制器动画到从frameOfPresentedViewInContainerView方法返回的frame rectangle中。

- (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];
    }
}

在presentation结束时,使用presentationTransitionDidEnd:方法来处理由于presentation取消而引起的任何清理。如果不满足其阈值条件,交互式animator对象可能会取消转场。当这种情况发生时,UIKit调用presentationTransitionDidEnd:方法,它的返回值是NO。当取消发生时,删除您在presentation开始时添加的任何自定义视图,并将任何其他视图返回到它们以前的配置,如下代码所示。

- (void)presentationTransitionDidEnd:(BOOL)completed {
    // If the presentation was canceled, remove the dimming view.
    if (!completed)
        [self.dimmingView removeFromSuperview];
}

当视图控制器被dismissed时,使用dismissalTransitionDidEnd:方法从视图层次结构中移除你的自定义视图。如果你想让你的视图消失动画化,在dismissalTransitionDidEnd:方法中设置那些动画。下面代码展示了在前面的示例中移除dimming view的两种方法的实现。始终检查dismissalTransitionDidEnd:方法的参数,以查看dismissal是否成功或被取消。

- (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];
}

Vending Your Presentation Controller to UIKit

当呈现一个视图控制器时,执行以下操作来使用您的自定义presentation控制器显示它:

  1. 将当前视图控制器的modalPresentationStyle属性设置为UIModalPresentationCustom
  2. 将一个转场代理分配给被presented视图控制器的transitioningDelegate属性
  3. 实现presentationControllerForPresentedViewController:presentingViewController:sourceViewController:转场代理的方法。

在需要你的presentation控制器,UIKit调用转场代理的presentationControllerForPresentedViewController:presentingViewController:sourceViewController:方法。这个方法的实现应该与下面代码中的方法一样简单。只需创建presentation控制器,配置它并返回它。如果你从这个方法返回nil, UIKit会用全屏显示风格来显示视图控制器。

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

推荐阅读更多精彩内容