自iOS 7以来,您可以在各种情况下(推送、弹出、模态等)轻松创建自定义视图控制器过渡。该项目提供了一个可以在项目中直接使用的自定义动画库。它还包含多个“交互控制器”,可以与任何自定义动画一起使用,以便使过渡具有交互性。
库中目前包含以下动画,可以通过滑动或捏合手势使其具有交互性。
翻转 | 折叠 | 淡入淡出 | 爆炸 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
翻转 | 卡片 | NatGeo | 门户 |
![]() |
![]() |
![]() |
![]() |
立方体 | 平移 | ||
![]() |
![]() |
以下提供了一些简要的概念介绍,更详细的介绍,我强烈建议阅读iOS 7 By Tutorials的第3章(就是我写的!) -听说其他15章也相当不错;(-”)
涉及自定义过渡的两个关键类
注意:动画和交互控制器完全独立,这意味着你可以将任何交互控制器与任何动画控制器连接起来——这真是太棒了。
本节简要概述了将自定义视图控制器转换添加到项目中所需的步骤。您还可以查看示例应用的代码(在TransitionsDemo
文件夹中)以供参考。如果您已经了解iOS 7自定义视图控制器转换的工作原理,则可以跳过本节!
您可以通过几种方式将此库中的转换集成到代码中
VCTransitionsLibrary
的引用。AnimationControllers
和InteractionControllers
文件夹中包含所有所需的代码。AnimationControllers
文件夹包含多个动画控制器,它们提供自定义转换,可以按以下方式集成到您的项目中
使用UIViewControllerTransitioningDelegate
协议来提供呈现/消失转换的动画控制器。当一个视图控制器被呈现或消失时,所呈现或消失的视图控制器的transitioningDelegate
属性被用来提供这个代理。在响应呈现时的animationControllerForPresentedController: presentingController: sourceController:
消息中返回一个动画控制器,在消失时返回animationControllerForDismissedController:
。
UINavigationControllerDelegate
协议中包含可用来提供动画控制器的方法。简单地返回一个动画控制器来响应navigationController: animationControllerForOperation: fromViewController: toViewController:
消息。
注意这个消息有一个‘operation’参数,它可以让你为推送和弹出操作返回不同的动画。此库中的所有动画控制器都是CEReversibleAnimationController
的子类,这允许你反向播放动画。这通常与导航控制器一起使用,如下所示
- (id<UIViewControllerAnimatedTransitioning>)navigationController:
(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
// reverse the animation for 'pop' transitions
_animationController.reverse = operation == UINavigationControllerOperationPop;
return _animationController;
}
UITabBarControllerDelegate
协议中包含可用来提供动画控制器的方法。简单地返回一个动画控制器来响应tabBarController: animationControllerForTransitionFromViewController: toViewController:
消息。
为了确定动画方向,您可以比较两个视图控制器的索引,如下所示
- (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
animationControllerForTransitionFromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
NSUInteger fromVCIndex = [tabBarController.viewControllers indexOfObject:fromVC];
NSUInteger toVCIndex = [tabBarController.viewControllers indexOfObject:toVC];
_animationController.reverse = fromVCIndex < toVCIndex;
return _animationController;
}
交互控制器与动画控制器协同工作,使得转换成为可交互的,即允许用户使用手势控制转换。这种交互性使用户可以向前移动、向后移动,甚至取消转换。
交互控制器负责向视图添加手势识别器,并在用户手势触发时启动导航。
用于提供动画控制器的UIViewControllerTransitioningDelegate
协议也用于提供交互控制器。以下是一个示例实现,它使用滑动交互和翻页动画
// instance variables, typically instantiated in your init method
CEFlipAnimationController *_animationController;
CESwipeInteractionController *_interactionController;
- (id<UIViewControllerAnimatedTransitioning>)
animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source {
// allow the interaction controller to wire-up its gesture recognisers
[_interactionController wireToViewController:presented
forOperation:CEInteractionOperationDismiss];
_animationController.reverse = NO;
return _animationController;
}
- (id<UIViewControllerAnimatedTransitioning>)
animationControllerForDismissedController:(UIViewController *)dismissed {
_animationController.reverse = YES;
return _animationController;
}
- (id<UIViewControllerInteractiveTransitioning>)
interactionControllerForDismissal:
(id<UIViewControllerAnimatedTransitioning>)animator {
// provide the interaction controller, if an interactive transition is in progress
return _interactionController.interactionInProgress
? _interactionController : nil;
}
请注意,在上面的代码中检查了交互控制器的interactionInProgress
属性。这是因为您可能还希望允许用户通过按钮以及通过交互来删除视图控制器。另外,您必须告诉交互控制器它应该执行的操作(例如:推送、取消)。
UINavigationControllerDelegate
协议还有一个返回交互控制器的方法。以下是一个通常的实现,它与上面的模式相同
// instance variables, typically instantiated in your init method
CEFlipAnimationController *_animationController;
CESwipeInteractionController *_interactionController;
- (id<UIViewControllerAnimatedTransitioning>)
navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
// wire the interaction controller to the to- view controller
[_interactionController wireToViewController:toVC
forOperation:CEInteractionOperationPop];
_animationController.reverse = operation == UINavigationControllerOperationPop;
return _animationController.reverse;
}
- (id <UIViewControllerInteractiveTransitioning>)
navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController {
// provide the interaction controller, if an interactive transition is in progress
return _interactionController.interactionInProgress
? _interactionController : nil;
}
UITabBarControllerDelegate
协议也有一个返回交互控制器的方法。与上面的导航控制器示例一样,交互控制器需要将其手势识别器添加到标签控制器导航之间的视图控制器中。不幸的是,当第一个视图控制器呈现时,标签代理方法不会触发,所以我选择了使用键值观察的稍显混乱的实现。
@implementation TabBarViewController {
CEFoldAnimationController *_animationController;
CESwipeInteractionController *_swipeInteractionController;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
self.delegate = self;
// create the interaction / animation controllers
_swipeInteractionController = [CESwipeInteractionController new];
_animationController = [CEFoldAnimationController new];
_animationController.folds = 3;
// observe changes in the currently presented view controller
[self addObserver:self
forKeyPath:@"selectedViewController"
options:NSKeyValueObservingOptionNew
context:nil];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqualToString:@"selectedViewController"] )
{
// wire the interaction controller to the view controller
[_swipeInteractionController wireToViewController:self.selectedViewController
forOperation:CEInteractionOperationTab];
}
}
- (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
animationControllerForTransitionFromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
NSUInteger fromVCIndex = [tabBarController.viewControllers indexOfObject:fromVC];
NSUInteger toVCIndex = [tabBarController.viewControllers indexOfObject:toVC];
_animationController.reverse = fromVCIndex < toVCIndex;
return _animationController;
}
-(id<UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
{
return _swipeInteractionController.interactionInProgress ? _swipeInteractionController : nil;
}
@end
以下是对各种过渡效果的图形说明。所有动画控制器都有一个duration
属性来配置动画时长。
使用纸张折叠风格的过渡在两个视图控制器之间进行动画。您可以通过folds
属性配置折叠的次数。
使用翻页过渡在两个视图控制器之间进行动画。
使用受启发于国家地理城市指南的过渡在两个视图控制器之间进行动画。它是通过MHNatGeoViewControllerTransition到iOS7 API进行适配的。
通过执行3D翻转以显示目标视图背面来在两个视图控制器之间进行动画。翻转动画有一个flipDirection
属性指定翻转方向。
通过简单的交叉渐变在两个视图控制器之间进行动画。
通过将来源视图控制器切成许多小片,然后随机旋转和缩小它们,在两个视图控制器之间进行动画。
给人一种视图控制器推动另一个视图控制器到后面的印象。它看起来比这些静态截图酷多了!
(由Tope - AppDesignVault提供)
在中间部分露出底下的视图控制器。
(由FreddyF提供)
这种过渡效果看起来像是在旋转立方体的表面。
(由Andrés Brun提供)