ViewController Programming Guide 笔记(七)

Creating Custom Presentations

一个 presentation controller 可以做下面这些事情:

  • 设置 presented view controller 的尺寸
  • 添加 自定义 View 改变 presented content 的外观
  • 自定义 Views 提供 转场动画
  • 当 app's 旋转时自动适应

UIKit 默认提供了最基本样式的 presentation controllers,你可以设置 presentation style 为 UIModalPresentationCustom 来提供自己的

创建自己的 presentation controllers 对象,然后提供给相应的 presentation controllers

一、The Custom Presentation Process

一般 presentation style 是自定义的话,UIKit 会调用 presentation controller 的方法,在这些方法中,你可以设置自定义 Views,然后把他们移动(动画的方式)到相应位置。

presentation controller 通常和 animator objects 一起配合来实现所有的转场,animator objects 负责 VC 在屏幕显示部分内容的动画,而 presentation controller 负责剩余的所有动画。

一般 presentation controller 负责他自己的 Views,但你也可以覆盖 presentedView 方法,让 animator objects 来接手

presentation 过程

  1. 调用 transitioning delegatepresentationControllerForPresentedViewController:presentingViewController:sourceViewController: 方法来 获取 自定义的 presentation controller
  2. transitioning delegate 请求 animator 对象(交互 or 非交互)
  3. 调用 presentation controller 的 presentationTransitionWillBegin 方法,你可以在该方法中添加自定义的 Views 并设置
  4. 通过 presentation controller 得到 presentedView,该 View 其实就是 presentedVC 的 root view,如果你要在 presentedView 方法中设置并返回自定义的 View,一定要将原 root view 嵌入到你的 view hierarchy 中
  5. 执行转场动画。在转场动画中 UIKit 会调用 presentation controller 下面两个方法,你可以在这两个方法中调整自定义 View 的布局
    • containerViewWillLayoutSubviews
    • containerViewDidLayoutSubviews
  6. 结束时调用 presentationTransitionDidEnd:

dismissal 过程 同样也是 6 步,不同的是 1,3,6 步

    1. 从当前可见的 VC 中 获取 presentation controller
    1. 调用 dismissalTransitionWillBegin
    1. 完成后调用 dismissalTransitionDidEnd:

在 Presentation 过程中 frameOfPresentedViewInContainerViewpresentedView 这两个方法会被调用多次,因此不要在里面做一些昂贵的操作,比如设置 view hierarchy

二、Creating a Custom Presentation Controller

创建一个自定义的 presentation controller 考虑下面五个问题:

  1. 你想添加的 View 是什么?
  2. 你想要的动画效果是什么?
  3. presentedVC 的尺寸是什么?
  4. 在 horizontally regular 和 horizontally compact 下,presentation 该如何处理?
  5. 完成后,presentingVC 的 View 是否应被移除?

这些问题对应着需要 重载 UIPresentationController 类的不同方法

1. Setting the Frame of the Presented View Controller

默认 presentedVC 的尺寸和 容器尺寸是一致的,你可以通过重载 frameOfPresentedViewInContainerView 方法来改变

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

2. Managing and Animating Custom Views

presentation controller 负责创建并管理着所有和 presentation 相关的 自定义 Views,下面在初始化方法中创建了一个 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;
}

将自定义 Views 在屏幕上动画起来使用 presentationTransitionWillBegin 方法,不要在该方法中修改 presented view

- (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: 做一些清理工作,如果是交互式转场,中间取消了转场,该方法返回 NO,也要做一些清理工作,如下:

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

dismissed 的过程也差不多:

- (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 controller,你需要做以下几件事:

  • 设置 presentedVC 的 modalPresentationStyle 为 .Custom
  • 创建一个 transitioning delegate 对象,然后分配给 presentedVC 的 transitioningDelegate
  • transitioning delegate 对象中实现 presentationControllerForPresentedViewController:presentingViewController:sourceViewController:

你在上面的方法中创建一个 presentation controller,设置并返回

- (UIPresentationController *)presentationControllerForPresentedViewController:
                                 (UIViewController *)presented
        presentingViewController:(UIViewController *)presenting
            sourceViewController:(UIViewController *)source {

    MyPresentationController* myPresentation = [[MyPresentationController]
       initWithPresentedViewController:presented presentingViewController:presenting];

    return myPresentation;
}

四、Adapting to Different Size Classes

当 presentation 已经在屏幕上的时候,如果下面的 traits容器 View 的尺寸发生变化,UIKit 会第一时间通知 presentation controller。这些改变通常是设备旋转引起的,你可以使用 traitsize notifications 来调整你的 presentation’s custom views 并根据适时地更新 presentation style


-EOF-

如果感觉此文对你有帮助,请随意打赏支持作者 😘

chengway

认清生活真相之后依然热爱它!

Subscribe to Talk is cheap, Show me the world!

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!