iOS之动画集合(持续更新中...)
---------- CATransition(转场动画) ----------
先看几种效果图(差不多有10种效果,为便于阅读,我都放在了一个gif里面,大概1分钟左右,中间以停顿时间为间隔)
animation.gif
在控制器里创建一个ImageView接收图片
{
UIImageView *_imageView;
int _index;//图片索引
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
_index = 1;
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 300, 450)];
_imageView.image = [UIImage imageNamed:@"1.jpg"];
_imageView.center = self.view.center;
_imageView.backgroundColor = [UIColor redColor];
[self.view addSubview:_imageView];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
_index ++;
if (_index == 4) {
_index = 1;
}
[_imageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg", _index]]];
CATransition *animation = [CATransition animation];
/*
Fade 逐渐消失;
Reveal 旧的视图移走显示出新的视图;
Push 旧的视图移走,新的视图移进来;
MoveIn 新的视图把旧的视图掩盖
*/
// animation.type = kCATransitionFade;
/*这类是API引入的,在苹果官网是不会承认的,所以不建议使用
1.animation.type = @"cube"; //立方体效果
*2.animation.type = @"suckEffect";//犹如一块布被抽走
*3. animation.type = @"oglFlip"; //上下翻转效果
*4. animation.type = @"rippleEffect"; //滴水效果
*5. animation.type = @"pageCurl"; //向左翻页
*6.animation.type = @"pageUnCurl"; //向下翻页
*/
animation.type = @"cube";//动画过渡类型
//从哪个方向开始,top bottom left right
animation.subtype = kCATransitionFromLeft;//动画过渡方向
//动画时间间隔
animation.duration = 1.5;
//动画的切换时间速度
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
// 动画起点(在整体动画的百分比)
// animation.startProgress = 0.5;
// 动画终点(在整体动画的百分比)
// animation.endProgress = 0.5;
//视图上加载动画(通过后面的forKey属性,在别的地方可以拿到这个动画的Key值)
[_imageView.layer addAnimation:animation forKey:nil];
}
-
CAMediaTiming协议
CAMediaTiming
协议定义了在一段动画内用来控制逝去时间的属性的集合,CALayer
和CAAnimation
都实现了这个协议。
duration
和repeatCount
代表持续和重复,默认都是0,但这不意味着动画时长为0秒,或者0次,这里的0仅仅代表了“默认”,也就是0.25秒和1次。
创建重复动画的另一种方式是使用repeatDuration
属性,它让动画重复一个指定的时间,而不是指定次数。还可以设置一个叫做autoreverses
的属性(BOOL类型),可以在动画结束后执行逆动画。
🌰项目拓展
切换控制器的时候,给NavigationController设置个转场动画,效果图
代码实现如下
CATransition *animation = [CATransition animation];
animation.type = @"cube";
animation.duration = 0.5;
animation.subtype = kCATransitionFromTop;
[self.navigationController.view.layer addAnimation:animation forKey:nil];
CATransitionViewController *VC = [[CATransitionViewController alloc]init];
[self.navigationController pushViewController:VC animated:YES];
---------- CABasicAnimation ----------
🌰实现简单的一个动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
//动画时间
animation.duration = 0.8;
//动画起始值和终止值的设置
animation.fromValue = @(0.8);
animation.toValue = @(0.8);
//一个时间函数,表示它以怎么样的时间运行
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
animation.repeatCount = HUGE_VALF;
animation.repeatDuration = 2;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
//添加动画
[self.btn.layer addAnimation:animation forKey:@"后面可以通过这个key值拿到这个动画的标识"];
相关属性
keyPath :要改变的属性名称(传字符串)
fromValue:keyPath相应属性的初始值
toValue:keyPath相应属性的结束值
timingFunction:动画随时间运行的关系
一些常见的animationWithKeyPath值总结
值 | 说明 | 使用形式 |
---|---|---|
transform.scale | 比例转化 | @(0.8) |
transform.scale.x | 宽的比例 | @(0.8) |
transform.scale.y | 高的比例 | @(0.8) |
transform.rotation.x | 围绕x轴旋转 | @(M_PI) |
transform.rotation.y | 围绕y轴旋转 | @(M_PI) |
transform.rotation.z | 围绕z轴旋转 | @(M_PI) |
cornerRadius | 圆角的设置 | @(50) |
backgroundColor | 背景颜色的变化 | (id)[UIColor redColor].CGColor |
bounds | 大小,中心不变 | [NSValue valueWithCGRect:CGRectMake:(0,0,200,200)] |
position | 位置(中心点的改变) | [NSValue valueWithCGPoint:CGPointMake:(300,300)] |
contents | 内容(UIImageView的图片) | imageAnimation.toValue = (id)[UIImage imageNamed:@"1"].CGImage |
opacity | 透明度 | @(0.7) |
contentsRect.size.width | 横向拉伸缩放 | @(0.4)//0~1之间的数字 |
----- CAKeyframeAnimation(关键帧动画) -----
🌰实现简单的一个动画
CAFrameAnimation.gif
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
NSArray *rotationArr = @[@(M_PI_4),@(-M_PI_4),@(M_PI_4)];
animation.values = rotationArr;
animation.rotationMode = kCAAnimationRotateAuto; //方向
animation.duration = 3.0f;
animation.keyTimes = @[@0.2 ,@0.8 ,@1.0];
//animation.path = bezierPath.CGPath;
animation.repeatCount = HUGE_VALF;
[self.imageView.layer addAnimation:animation forKey:@"后面可以通过这个key值拿到这个动画的标识"];
属性说明
values:上述的NSArray对象。里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
path:可以设置一个CGPathRef、CGMutablePathRef,让图层按照路径轨迹移动。path只对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略
keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧。如果没有设置keyTimes,各个关键帧的时间是平分的
bezierPath:贝赛尔曲线路径,为动画提供一个动画移动的路线。
---------- UIBezierPath (贝赛尔曲线) ----------
简单的画一个曲线:
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
[bezierPath moveToPoint:CGPointMake(0, 450)];
[bezierPath addCurveToPoint:CGPointMake(self.view.width, 450) controlPoint1:CGPointMake(self.view.width/2, 450-200) controlPoint2:CGPointMake(self.view.width/2, 450+200)];//一个曲线
//路径样式
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = bezierPath.CGPath;
shapeLayer.fillColor = [UIColor clearColor].CGColor; //填充色<默认黑色>
shapeLayer.strokeColor = [UIColor blueColor].CGColor; //线色
shapeLayer.lineWidth = 2;
[self.view.layer addSublayer:shapeLayer];
UIBezierPath: 创建一个路径,画出一条曲线
CAShapeLayer: 对上面的线进行属性上的设置。最后添加到一个layer上。
UIBezierPath具体详解
---------- CAAnimationGroup(动画组) ----------
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[animation,basicAnimation];
animationGroup.duration = 4;
animation.repeatCount = 9;
[_imageLayer addAnimation:animationGroup forKey:nill];
属性说明
animations:用来保存一组动画对象的NSArray
默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间
---------- POP(Spring弹簧效果)----------
1、简单使用-效果图
Spring1.gif
实现代码
先Pod
pod 'pop','~>1.0.10'
引入头文件
#import "POPSpringAnimation.h"
#import "POPBasicAnimation.h"
设置参数
static CGFloat const DCAnimationDelay = 0.1;//速度
static CGFloat const DCSpringFactor = 7;//幅度
使用
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.size = CGSizeMake(100, 80);
btn.center = CGPointMake(self.view.centerX, self.view.centerY);
btn.backgroundColor = [UIColor redColor];
[btn addTarget:self action:@selector(btnDidClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
-(void)btnDidClick:(UIButton *)btn
{
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
// 移动距离
animation.fromValue = [NSValue valueWithCGRect:CGRectMake(btn.x, 0, btn.width, btn.height)];//开始位置
animation.toValue = [NSValue valueWithCGRect:CGRectMake(btn.x, 200, btn.width, btn.height)];//结束位置
// 从当前 + 1s后开始
animation.beginTime = CACurrentMediaTime() + 1.0f;
// 弹力--晃动的幅度 (springSpeed速度)
animation.springBounciness = DCSpringFactor;
animation.springSpeed = DCAnimationDelay;
[btn pop_addAnimation:animation forKey:nil];
}
2、效果图
Spring2.gif
代码实现
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.size = CGSizeMake(100, 80);
btn.center = CGPointMake(self.view.centerX, self.view.centerY);
btn.backgroundColor = [UIColor redColor];
[btn addTarget:self action:@selector(btnDidClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(btn.x, CGRectGetMaxY(btn.frame)-200, 100, 60)];
label.backgroundColor = [UIColor lightGrayColor];
label.textColor = [UIColor redColor];
label.textAlignment = NSTextAlignmentCenter;
label.text = @"0.0";
self.label = label;
[self.view addSubview:label];
}
-(void)btnDidClick:(UIButton *)btn
{
// 初始化
POPBasicAnimation *anim = [POPBasicAnimation animation];
// 限时 1s. 2s.
anim.duration = 3.0;
POPAnimatableProperty * prop = [POPAnimatableProperty propertyWithName:@"count++" initializer:^(POPMutableAnimatableProperty *prop) {
prop.readBlock = ^(id obj, CGFloat values[]){ values[0] = [[obj description] floatValue]; };
prop.writeBlock = ^(id obj, const CGFloat values[])
{
[obj setText:[NSString stringWithFormat:@"%.2f",values[0]]];
};
prop.threshold = 0.01;
}];
anim.property = prop;
anim.fromValue = @(0.0);
anim.toValue = @(1314.52);
[self.label pop_addAnimation:anim forKey:@"counting"];
}
3、效果图
Spring3.gif
代码实现
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
CALayer *layer1 = [CALayer layer];
layer1.opacity = 1.0;
layer1.transform = CATransform3DIdentity;
layer1.masksToBounds = YES;
layer1.backgroundColor = [UIColor redColor].CGColor;
layer1.bounds = CGRectMake(0, 0, 100, 100);
layer1.position = CGPointMake(self.view.centerX, self.view.centerY);
layer1.cornerRadius = 50;
[self.view.layer addSublayer:layer1];
[self performAnimation:layer1];
}
- (void)performAnimation:(CALayer *)layer
{
[layer pop_removeAllAnimations];
POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
// anim.duration = 1.0;
static BOOL ani = YES;
if (ani) {
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
}else{
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.5, 1.5)];
}
ani = !ani;
anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
if (finished) {
[self performAnimation:layer];
}
};
[layer pop_addAnimation:anim forKey:@"Animation"];
}
项目拓展
效果图
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.size = CGSizeMake(100, 80);
btn.center = CGPointMake(self.view.centerX, self.view.centerY);
btn.backgroundColor = [UIColor redColor];
[btn addTarget:self action:@selector(btnDidClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
-(void)btnDidClick
{
[self setUpBackGroundView];
}
-(void)setUpBackGroundView{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UIView *backgroundView = [[UIView alloc]initWithFrame:self.view.bounds];
backgroundView.userInteractionEnabled = YES;
self.backgroundView = backgroundView;
[window addSubview:backgroundView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapDidClick)];
[backgroundView addGestureRecognizer:tap];
UIImageView *backgroundImage = [[UIImageView alloc]initWithFrame:backgroundView.bounds];
backgroundImage.image = [UIImage imageNamed:@"active_bj"];
backgroundImage.userInteractionEnabled = YES;
[backgroundView addSubview:backgroundImage];
UIButton *cancleBtn = [[UIButton alloc]initWithFrame:CGRectMake((backgroundImage.width - 44) * 0.5, backgroundImage.height - 44 *2, 44, 44)];
[cancleBtn setImage:[UIImage imageNamed:@"built_click"] forState:UIControlStateNormal];
[cancleBtn addTarget:self action:@selector(cancleBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
[backgroundView addSubview:cancleBtn];
NSArray *titles = @[@"你",@"就",@"说",@"我",@"帅",@"不",@"帅"];
int maxCols = 3;
CGFloat buttonW = self.backgroundView.width/3;
CGFloat buttonH = 95;
CGFloat buttonStartY = (self.backgroundView.height - 2 * buttonH) * 0.5;
CGFloat buttonStartX = 20;
CGFloat xMargin = (self.backgroundView.width - 2 * buttonStartX - maxCols * buttonW) / (maxCols - 1);
for (int i = 0; i<titles.count; i++) {
UIButton *button = [[UIButton alloc] init];
button.tag = i;
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.backgroundView addSubview:button];
// 设置内容
button.titleLabel.font = [UIFont systemFontOfSize:50];
[button setTitle:titles[i] forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:titles[i]] forState:UIControlStateNormal];
// 计算X\Y
int row = i / maxCols;
int col = i % maxCols;
CGFloat buttonX = buttonStartX + col * (xMargin + buttonW);
CGFloat buttonEndY = buttonStartY + row * buttonH;
CGFloat buttonBeginY = buttonEndY - self.backgroundView.height;
// 按钮动画
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];
anim.fromValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonBeginY, buttonW, buttonH)];
anim.toValue = [NSValue valueWithCGRect:CGRectMake(buttonX, buttonEndY, buttonW, buttonH)];
anim.springBounciness = DCSpringFactor;
anim.springSpeed = DCSpringFactor;
anim.beginTime = CACurrentMediaTime() + DCAnimationDelay * i;
[button pop_addAnimation:anim forKey:nil];
}
}
- (void)buttonClick:(UIButton *)button
{
[self cancelWithCompletionBlock:^{
if (button.tag == 0 || button.tag == 1 || button.tag == 2) {
NSLog(@"0 1 2");
}else if (button.tag == 3){
NSLog(@"3");
}else if (button.tag == 4){
NSLog(@"4");
}else if (button.tag == 5){
NSLog(@"5");
}else if (button.tag == 6){
NSLog(@"6");
}
UIViewController *vv = [[UIViewController alloc]init];
vv.view.backgroundColor = [UIColor lightGrayColor];
[self.navigationController pushViewController:vv animated:YES];
}];
}
/**
* 先执行退出动画, 动画完毕后执行completionBlock
*/
- (void)cancelWithCompletionBlock:(void (^)(void))completionBlock
{
// 让控制器的view不能被点击
self.backgroundView.userInteractionEnabled = NO;
int beginIndex = 2;
for (int i = beginIndex; i<self.backgroundView.subviews.count; i++) {
UIView *subview = self.backgroundView.subviews[i];
// 基本动画
POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
CGFloat centerY = subview.centerY + [UIScreen mainScreen].bounds.size.height;
// 动画的执行节奏(一开始很慢, 后面很快)
// anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(subview.centerX, centerY)];
anim.beginTime = CACurrentMediaTime() + (i - beginIndex) * DCAnimationDelay;
[subview pop_addAnimation:anim forKey:nil];
// 监听最后一个动画
if (i == self.backgroundView.subviews.count - 1) {
[anim setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
// [self dismissViewControllerAnimated:NO completion:nil];
self.backgroundView.hidden = YES;
// 执行传进来的completionBlock参数
!completionBlock ? : completionBlock();
}];
}
}
}
-(void)tapDidClick
{
[self cancelWithCompletionBlock:nil];
}
-(void)cancleBtnDidClick
{
[self cancelWithCompletionBlock:nil];
}