天天品尝iOS7甜点 :: Day 10 :: Custom UIViewController Transitions

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


一些被要求的新特性为用户之间切换不同视图控制器的定制动画效果,针对UINavigationController栈和模态表示。iOS7中介绍此动能——这两种自动转换和互动转换(这些转换是用户来进行控制的)。今天本文就看介绍自动转换是如何工作的,并且实现navigation controller上面的push和pop一个平滑的效果。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

自定义转换的世界中充满了协议。然而,例如我们要创建只需要查看一小部分。要进行交互转换和模态展示交互,需要一些额外的协议。

在一个视图控制器中使用push和pop转换,我们需要确定那些转换是我们需要用到的,UINavigationControl有一个delegate可能供使用。这个delegate必须是UINavigationControllerDelegate协议,它具有4个新的方法提供个转换使用。我们感兴趣的是当前是能够提供给我们进行自一定转换的方法:

1
2
3
4
- (id<UIViewControllerAnimatedTransitioning>)navigationController:
animationControllerForOperation:
fromViewController:
toViewController:

当navigation controller进行视图转换(不管是自己写的程序还是storyboard中segue)的时候都会调用这个方法。我们被告知视图控制器从哪个到哪个的过滤,所以在这一点上我们可以进行不同的转换效果。

我们创建一个类,来扮演navigation controller代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@interface SCNavControllerDelegate : NSObject <UINavigationControllerDelegate>
@end
```

<!-- more -->

有一个很简单的实现:

``` objc
@implementation SCNavControllerDelegate
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
return [SCFadeTransition new];
}
@end
```

我们希望所有的转换都是相同的(不管是前进还是后退),所以我们可以每一次都返回一个`SCFadeTransition`对象.我们将会在下一阶段看看这个对象到底是什么。

设置这个delegate是非常简单的,代码如下所示:

``` objc
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
_navDelegate = [SCNavControllerDelegate new];
self.delegate = _navDelegate;
}
return self;
}

这里的_navDelegateid<UINavigationControllerDelegate>的一个实例。

Creating a custom transition

我们发现那个delegate需要返回一些转换对象。那些返回的转行对象必须实现了UIViewControllerAnimatedTransitioning协议。这个协议里面有3个方法,其中2个方法是必须要实现的:

  • transitionDuration:(必要).这个方法返回动画的时长。这是使用的操作系统同步其他事件——如动画导航栏导航控制器。
  • animateTransition:(必要).这个方法是你用来真实的实现视图控制器之间转换的实现。我们提供了一个对象,让我们获得我们需要的不同组件。
  • animationEnded:这个方法是在你的转换完成之后进行调用。

我们目前只需要实现2个必要的方法来让我们的平滑的转换工作,创建一个对象来实现协议:

1
2
@interface SCFadeTransition : NSObject <UIViewControllerAnimatedTransitioning>
@end

实现transitionDuration:方法,实现体十分的简单:

1
2
3
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 2.0;
}

animateTransition:方面被调用的时候,我们就得到一个实现了UIViewControllerContextTransitioning协议的对象,它能够使我们获得完成动画所需要的细节内容。我们要用到的第一个方法是viewControllerForKey:,这个方法可能允许我们获得两个视图控制器来实现转换:

1
2
3
// Get the two view controllers
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

这个上下文对象还提供了一个UIView来执行动画,这个是通过这个方法获得的containerView:

1
2
// Get the container view - where the animation has to happen
UIView *containerView = [transitionContext containerView];

我们需要确保转换的视图控制器的视图是上述视图(containerView)的子视图。就像我们转换的就是子视图而已。

1
2
3
// Add the two VC views to the container
[containerView addSubview:fromVC.view];
[containerView addSubview:toVC.view];

我们不需要看到要转换到的那个视图,所以我们需要把它设置为透明:

1
toVC.view.alpha = 0.0;

现在我们到了真正要实现动画的地方了,由于我们需要在两个视图控制器上面实现一个简单的平滑效果,我们可以使用UIView中的动画函数:

1
2
3
4
5
6
7
8
9
10
11
12
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
options:0
animations:^{
toVC.view.alpha = 1.f;
}
completion:^(BOOL finished) {
// Let's get rid of the old VC view
[fromVC.view removeFromSuperview];
// And then we need to tell the context that we're done
[transitionContext completeTransition:YES];
}];

Summary - 总结

与我们做的!它实际上是相当简单协议。我们唯一要做的就是设置已经存在的navigation view controller的delegate。剩下的工作是实现delegate类,设置一个过渡对象,然后执行动画效果。

本文翻译自:iOS7 Day-by-Day :: Day 10 :: Custom UIViewController Transitions

文章目录
  1. 1. Navigation Controller Delegate
  2. 2. Creating a custom transition
  3. 3. Summary - 总结
,