View Controller 自定义转场动画

自定义转场动画

iOS 7 中最让我激动的特性之一就是提供了新的 API 来支持自定义 view contrioller 之间的转场动画。iOS 7 发布之前,我自己写过一些 view controller 之间的转场动画,这是一个比较头疼的过程,而且这种做法并不被苹果完全地支持,尤其是如果你想让这个转场动画有交互式的效果就更难了。

在继续阅读之前,我需要先声明一下:这个 API 是新近才发布的,目前还没有所谓的最佳实践。通常来说,开发者需要探索几个月才能得出关于新 API 的最佳实践。因此请将本文看做对一个新 API 的探索,而非关于这个新 API 的最佳实践介绍。如果您有更好的关于这个 API 的实践,请不吝赐教,我们会把您的实践更新到这篇文章中。

在开始研究新的 API 之间,我们先来看看在 iOS 7 中 navigation controller 之间的默认的行为发生了那些改变:在 navigation controller 中,切换两个 view controller 的动画变得更有交互性。比方说你想要 pop 一个 view controller 出去,你可以用手指从屏幕的左边缘开始拖动,慢慢地把当前的 view controller 向右拖出屏幕去。

接下来,我们来看看这个新 API。很有趣的一个现象是,这部分 API 大量的使用了协议而不是具体的对象。这初看起来有点奇怪,但我个人更喜欢这样的 API 设计,因为这种设计给了我们这些开发者更大的灵活性。下面,让我们来做件简单的事情:在 Navigation Controller 中,实现一个自定义的 push 动画效果(本文中的示例代码托管在 Github)。为了完成这个任务,需要实现 UINavigationControllerDelegate 中的新方法:

编者注 原文的作者在 Github 上面的示例代码和文章中的代码有一些出入(比如下面这里是 Push,但是在示例代码中是 Pop)。如果需要,您也可以参考这个修正版示例代码,和文章的代码差异要小一点。

- (id<UIViewControllerAnimatedTransitioning>)
                   navigationController:(UINavigationController *)navigationController
        animationControllerForOperation:(UINavigationControllerOperation)operation
                     fromViewController:(UIViewController*)fromVC
                       toViewController:(UIViewController*)toVC
{    if (operation == UINavigationControllerOperationPush) {        return self.animator;
    }    return nil;
}

从上面的代码可以看出,我们可以根据不同的 operation(Push 或 Pop)返回不同的 animator。我们可以把 animator 存到一个属性中,从而在多个 operation 之间实现共享,或者我们也可以为每个 operation 都创建一个新的 animator 对象,这里的灵活性很大。

为了让动画运行起来,我们创建一个自定义类,并且实现 UIViewControllerContextTransitioning 这个协议:

@interface Animator : NSObject <UIViewControllerAnimatedTransitioning>@end

这个协议要求我们实现两个方法,其中一个定义了动画的持续时间:

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{    return 0.25;
}

另一个方法描述整个动画的执行效果:

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{	UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];	UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
	[[transitionContext containerView] addSubview:toViewController.view];
	toViewController.view.alpha = 0;
	[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
		fromViewController.view.transform = CGAffineTransformMakeScale(0.1, 0.1);
		toViewController.view.alpha = 1;
	} completion:^(BOOL finished) {
		fromViewController.view.transform = CGAffineTransformIdentity;
		[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
	}];
}

从上面的例子中,你可以看到如何运用协议的:这个方法中通过接受一个类型为 id<UIViewControllerContextTransitioning> 的参数,来获取 transition context。值得注意的是,执行完动画之后,我们需要调用 transitionContext 的 completeTransition: 这个方法来更新 view controller 的状态。剩下的代码和 iOS 7 之前的一样了,我们从 transition context 中得到了需要做转场的两个 view controller,然后使用最简单的 UIView animation 来实现了转场动画。这就是全部代码了,我们已经实现了一个缩放效果的转场动画。

注意,这里只是为 Push 操作实现了自定义效果的转场动画,对于 Pop 操作,还是会使用默认的滑动效果,另外,上面我们实现的转场动画无法交互,下面我们就来看看解决这个问题。

猿圈 (ID: CodePush ) (←长按复制)

为程序员提供最优质的博文、最精彩的讨论、最实用的开发资源;提供最新最全的编程学习资料:PHP、Objective-C、Java、Swift、C/C++函数库、.NET Framework类库、J2SE API等等。并不定期奉送各种福利。

(复制微信号,搜索公众号即可关注)

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章