上次说了一下mask,这次来讲一下如何用mask来实现这个动画,关于自定义转场动画的内容可以查看这篇文章,要实现的动画如下:
首页实现两个viewcontroller之间的push和pop,示例代码如下:
第一个viewcontroller
- (void)viewDidLoad {
[super viewDidLoad];
//设置背景色
self.view.backgroundColor = [UIColor greenColor];
//放一张图片
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
imageView.center = self.view.center;
imageView.image = [UIImage imageNamed:@"ipad.jpg"];
[self.view addSubview:imageView];
//创建按钮
_btn = [UIButton buttonWithType:UIButtonTypeCustom];
_btn.backgroundColor = [UIColor blackColor];
_btn.layer.cornerRadius = 22;
_btn.frame = CGRectMake(self.view.frame.size.width-20-44, 20, 44, 44);
[_btn addTarget:self action:@selector(goNext) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btn];
}
//push到下一个
- (void)goNext
{
SecondViewController *sec = [[SecondViewController alloc]init];
[self.navigationController pushViewController:sec animated:YES];
}
第二个viewcontroller:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor yellowColor];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
imageView.center = self.view.center;
imageView.image = [UIImage imageNamed:@"iphone.jpg"];
[self.view addSubview:imageView];
_btn = [UIButton buttonWithType:UIButtonTypeCustom];
_btn.backgroundColor = [UIColor blackColor];
_btn.layer.cornerRadius = 22;
_btn.frame = CGRectMake(self.view.frame.size.width-20-44, 20, 44, 44);
[_btn addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btn];
}
- (void)goBack
{
[self.navigationController popViewControllerAnimated:YES];
}
效果如下:
让这两个viewcontroller遵守 <UINavigationControllerDelegate> 协议
@interface ViewController ()<UINavigationControllerDelegate>
@interface SecondViewController ()<UINavigationControllerDelegate>
都设置好代理:
- (void)viewWillAppear:(BOOL)animated
{
self.navigationController.delegate = self;
}
- (void)viewWillDisappear:(BOOL)animated
{
self.navigationController.delegate = nil;
}
都实现协议方法(返回一个自定义动画对象):
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
return myAnimation;
}
接下来就是创建这个自定义的动画对象,创建一个类,遵守 < UIViewControllerAnimatedTransitioning > 协议,并且实现协议方法:
//.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface CircleAnimation : NSObject <UIViewControllerAnimatedTransitioning>
@end
//.m
#import "CircleAnimation.h"
#import "ViewController.h"
#import "SecondViewController.h"
@interface CircleAnimation ()
@property (assign, nonatomic) id <UIViewControllerContextTransitioning> context;
@end
@implementation CircleAnimation
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 3.0;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
//得到上下文
self.context = transitionContext;
//获取容器视图
UIView *container = [transitionContext containerView];
//获取参与转场的viewcontroller
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//拿到btn,需要用到他的frame
UIButton *btn;
if ([fromVC isKindOfClass:[ViewController class]]) {
btn = ((ViewController*)fromVC).btn;
}
else if ([fromVC isKindOfClass:[SecondViewController class]]) {
btn = ((SecondViewController*)fromVC).btn;
}
[container addSubview:toVC.view];
//起始路径
UIBezierPath *initPath = [UIBezierPath bezierPathWithOvalInRect:btn.frame];
//大圆半径
CGFloat newR = sqrt(btn.center.x*btn.center.x + (btn.center.y-CGRectGetHeight(toVC.view.bounds))*(btn.center.y-CGRectGetHeight(toVC.view.bounds)));
//终点路径
UIBezierPath *finalPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(btn.frame, -newR, -newR)];
//创建一个遮罩
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = [finalPath CGPath];
toVC.view.layer.mask = maskLayer;
//创建动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.fromValue = (__bridge id)([initPath CGPath]);
animation.toValue = (__bridge id)([finalPath CGPath]);
animation.duration = [self transitionDuration:transitionContext];
animation.delegate = self;
//添加动画
[maskLayer addAnimation:animation forKey:@"path"];
}
//清理工作
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
[self.context viewControllerForKey:UITransitionContextToViewControllerKey].view.layer.mask = nil;
[self.context viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;
[self.context completeTransition:![self.context transitionWasCancelled]];
}
@end
在两个viewcontroller里创建该动画对象,并在实现的协议方法里,返回它:
- (void)viewDidLoad {
[super viewDidLoad];
_ani = [[CircleAnimation alloc]init];
//设置背景色
....
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
return _ani;
}
run!