http://blog.csdn.net/hmt20130412/article/details/39079905 這篇博客對於轉場動畫,我認爲講解得比較詳細了
在iOS7中,蘋果官方提供了幾個關鍵性的API,我這邊再次簡單總結下
1.在我們做轉場動畫的時候,需要實現幾個代理
A.動畫控制器 (Animation Controllers) 遵從 UIViewControllerAnimatedTransitioning 協議,並且負責實際執行動畫。
B.交互控制器 (Interaction Controllers) 通過遵從 UIViewControllerInteractiveTransitioning 協議來控制可交互式的轉場《暫時先不做》。
//我這邊就直接上例子,定義一個動畫繼承自NSObject,實現代理UIViewControllerAnimatedTransitioning
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, AnimationType) {
AnimationTypePush,
AnimationTypePop,
};
@interface ChangeVCAnimationDele : NSObject<UIViewControllerAnimatedTransitioning>
@property (nonatomic,assign)AnimationType actionType; /**< 當前的動畫是push還是pop*/
@property (nonatomic,assign)CGPoint center;/**< 消失,顯示的中心點*/
@end
.h文件
#import "ChangeVCAnimationDele.h"
#define kAnimtionTime 0.5f
@interface ChangeVCAnimationDele ()
@property (nonatomic,strong)CAShapeLayer *maskLayer;
@property (nonatomic,strong)id<UIViewControllerContextTransitioning> transitionContext;
@property (nonatomic,weak)UIViewController *toVC;/**< 目標的VC*/
@property (nonatomic,weak)UIViewController *fromeVC; /**< 來源的VC*/
@end
@implementation ChangeVCAnimationDele
- (CAShapeLayer *)maskLayer {
if (!_maskLayer) {
_maskLayer = [[CAShapeLayer alloc] init];
}
return _maskLayer;
}
// 系統給出一個切換上下文,我們根據上下文環境返回這個切換所需要的花費時間
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return kAnimtionTime;
}
// 完成容器轉場動畫的主要方法,我們對於切換時的UIView的設置和動畫都在這個方法中完成
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
// 可以看做爲destination ViewController 目標VC
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 可以看做爲source ViewController
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
self.toVC = toViewController;
self.fromeVC = fromViewController;
self.transitionContext = transitionContext;
if (AnimationTypePush == self.actionType) {
[[transitionContext containerView] addSubview:toViewController.view];
//防止閃動,需要提前處理動畫結束的代碼
[NSTimer scheduledTimerWithTimeInterval:kAnimtionTime target:self selector:@selector(animationFinish:) userInfo:nil repeats:NO];
[self show];
}
else {
[[transitionContext containerView] addSubview:toViewController.view];
[[transitionContext containerView] addSubview:fromViewController.view];
[self dismiss];
}
}
- (UIBezierPath *)bezierPathWithCenter:(CGPoint)center Radius:(CGFloat)radius {
CGRect rect = CGRectMake(center.x - radius, center.y - radius, radius * 2, radius * 2);
return [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
}
#pragma mark -
#pragma mark - push
- (void)show {
self.toVC.view.layer.mask = self.maskLayer;
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
pathAnimation.fromValue = (__bridge id _Nullable)([self bezierPathWithCenter:self.center Radius:0].CGPath);
pathAnimation.toValue = (__bridge id _Nullable)([self bezierPathWithCenter:self.center Radius:1000].CGPath);
pathAnimation.duration = kAnimtionTime + 0.1;
// pathAnimation.delegate = self;
pathAnimation.removedOnCompletion = YES;
[self.maskLayer addAnimation:pathAnimation forKey:@"show"];
}
#pragma mark -
#pragma mark - POP
- (void)dismiss {
self.fromeVC.view.layer.mask = self.maskLayer;
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
pathAnimation.fromValue = (__bridge id _Nullable)([self bezierPathWithCenter:_center Radius:1000].CGPath);
pathAnimation.toValue = (__bridge id _Nullable)([self bezierPathWithCenter:_center Radius:0].CGPath);
pathAnimation.duration = kAnimtionTime;
pathAnimation.delegate = self;
pathAnimation.removedOnCompletion = YES;
[self.maskLayer addAnimation:pathAnimation forKey:@"dismiss"];
}
#pragma mark -
#pragma mark - 時間差,這個時候等動畫完成了,中間需要一段時間纔會執行代理,所以在push的時候需要提前處理操作,pop的時候需要延後處理,也就不要寫計時器的
//pop的時候用到
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
if (flag) {
[self.fromeVC.view removeFromSuperview];
[self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
self.toVC.view.layer.mask = nil;
}
}
//push的時候用到
- (void)animationFinish:(NSTimer *)timer {
[self.transitionContext completeTransition:![self.transitionContext transitionWasCancelled]];
self.toVC.view.layer.mask = nil;
}
@end
.m文件
到此時,基本動畫已經完成了,最後就是在適當的時候插入動畫了,來到push的VC
定義Navigation的代理《我這裏只做了push的,present是一樣的》
self.navigationController.delegate = self;
然後實現Navigation的代理- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
ChangeVCAnimationDele *animation = [[ChangeVCAnimationDele alloc]init];
if (operation == UINavigationControllerOperationPush) {
animation.actionType = AnimationTypePush;
}else {
animation.actionType = AnimationTypePop;
}
animation.center = self.customBtn.center;
return animation;
}