您的位置:首页 > 移动开发 > IOS开发

iOS自定义转场动画

2014-11-26 14:08 190 查看
在iOS程序里出现得最多的转场动画,就是UINavigationController的Push和Pop了,看多了就觉得有些无聊了,还好苹果提供了自定义转场动画的API,往下看。

首页,要明白既然转场动画是通过导航控制器来完成(UIViewController模态除外),那么就往UINavigationController看,既然是转场,那么在两个控制器切换的中间,就是转场动画发生的地方,一提到“将要出现”,“已经出现”,“将要消失”,“已经消失”,条件反射就想到了UINavigationController的代理方法:

@protocol UINavigationControllerDelegate <NSObject>

@optional

// Called when the navigation controller shows a new top view controller via a push, pop or setting of the view controller stack.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

- (NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);
- (UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);

- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);

@end


注意最后两个方法,就是它了,注意可用的iOS版本:NS_AVAILABLE_IOS(7_0)

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);
这个方法是讲的手势百分比交互,今天不谈,说最后一个方法,它的返回值是

id <UIViewControllerAnimatedTransitioning>,一个遵循UIViewControllerAnimatedTransitioning的对象,点开它:

@protocol UIViewControllerAnimatedTransitioning <NSObject>

// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
// synchronize with the main animation.
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext;
// This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

@optional
两个方法,第一个是返回动画持续时间,第二个是动画具体内容。

说了这么多理论,总结一下自定义转场动画大致的设置思路:
1、自定义一个继承自NSObject并且遵从UIViewControllerAnimatedTransitioning协议的类,里面实现协议方法,设置好动画时长和具体内容;
2、在转场动画发生的viewcontroller里,遵从UINavigationControllerDelegate协议,实现协议方法

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
在该方法里返回自定义的动画类的一个对象即可。

示例:



新建一个有两个viewcontroller的工程:FirstViewController、SecondViewcontroller,将FirstViewcontroller加到一个导航控制器里,它的view上有一个“push”按钮,点它可以将SecondViewController push进来,SecondViewController上有一个“pop”按钮,点它可以pop到FirstViewController,描述得已经很清楚了吧。
创建两个继承自NSObject的类,一个叫PushAnimation,一个叫PopAnimation,它们都遵循UIViewControllerAnimatedTransitioning协议:

@interface PushAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end

@interface PopAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end


在PushAnimation.h
//返回动画持续时间
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 2.0f;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
//获取起点controller
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

//获取终点controller
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

//获取转场容器视图
UIView *containerView = [transitionContext containerView];

//设置终点视图的frame
CGRect frame = [transitionContext initialFrameForViewController:fromVC];
CGRect offScreenFrame = frame;
//先将其设置到屏幕外边,通过动画进入
offScreenFrame.origin.x = offScreenFrame.size.width;
toVC.view.frame = offScreenFrame;

//添加视图
[containerView addSubview:toVC.view];

//执行动画
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
//设置缩放和透明度
fromVC.view.transform = CGAffineTransformMakeScale(0.8, 0.8);
fromVC.view.alpha = 0.5;
//设置位置
toVC.view.frame = frame;
} completion:^(BOOL finished) {
fromVC.view.transform = CGAffineTransformIdentity;
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}


在PopAnimation里实现下面方法(push的逆动画,其实可以只创建一个类,通过“顺”or“逆”来判断执行的动画):

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

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

UIView *containerView = [transitionContext containerView];

toVC.view.transform = CGAffineTransformMakeScale(0.8, 0.8);
toVC.view.alpha = 0.5;
CGRect frame = [transitionContext initialFrameForViewController:fromVC];
CGRect offScreenFrame = frame;
offScreenFrame.origin.x = offScreenFrame.size.width;

[containerView insertSubview:toVC.view belowSubview:fromVC.view];

[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toVC.view.transform = CGAffineTransformIdentity;
toVC.view.alpha = 1.0f;
fromVC.view.frame = offScreenFrame;
} completion:^(BOOL finished) {
fromVC.view.transform = CGAffineTransformIdentity;
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}


在FirstViewController.m里添加下面代码:

#import "PushAnimation.h"

@interface FirstViewController ()<UINavigationControllerDelegate>
{
PushAnimation *_pushAni;
}
@end

- (void)viewDidLoad {
[super viewDidLoad];
_pushAni = [PushAnimation new];
}

- (void)viewDidAppear:(BOOL)animated
{
self.navigationController.delegate = self;
[super viewDidAppear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
if (self.navigationController.delegate == self) {
self.navigationController.delegate = nil;
}
[super viewDidDisappear:animated];
}

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


同样,在SecondViewController里设置pop的动画代码,即可,更好的方法,可以写一个继承自UINavigationController的子类,统一实现协议方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: