学习一些常见的动画效果
编写自己的动画库
制作成CABasicAnimation的category
2.UIView动画
UIView封装的动画
[UIView animateWithDuration:2.0 animations:^{
NSLog(@"动画执行之前: %@",NSStringFromCGPoint(self.cutomView.center));
// 需要执行动画的代码
self.cutomView.center = CGPointMake(300, 300);
} completion:^(BOOL finished) {
// 动画执行完毕之后执行的代码
NSLog(@"动画执行之后: %@",NSStringFromCGPoint(self.cutomView.center));
}];
transform的组合效果
__weak typeof (self) unsafeSelf=self;
[UIView animateWithDuration:1.0 animations:^(void){
// unsafeSelf.button.transform=CGAffineTransformMakeScale(0.8, 1.2);
unsafeSelf.button.transform= CGAffineTransformScale(unsafeSelf.button.transform, 1.2, 1.2);
unsafeSelf.button.transform=CGAffineTransformTranslate(unsafeSelf.button.transform, 10, 20);
unsafeSelf.button.transform=CGAffineTransformRotate(unsafeSelf.button.transform, 0.25*M_PI);
} completion:^(BOOL finished){
}];
UIView 的动画
点击事件里面的动画,移动一个UIImageView
- (IBAction)startAnimation:(UIButton *)sender {
[UIView beginAnimations:nil context:nil];
//设定动画持续时间
[UIView setAnimationDuration:2];
//动画的内容
self.image.frame=CGRectMake(self.image.frame.origin.x, self.image.frame.origin.y+20,
self.image.frame.size.width, self.image.frame.size.height);
//动画结束
[UIView commitAnimations];
}
UIView中block形式的动画
UIView阻尼动画
-
播放图片的动画
给一个UIImageView播放动画
NSArray *myImages = [NSArray arrayWithObjects:
[UIImage imageNamed:@"1.jpg"],
[UIImage imageNamed:@"2.jpg"],
nil];
self.image.animationImages = myImages; //animationImages属性返回一个存放动画图片的数组
self.image.animationDuration = 1; //浏览整个图片一次所用的时间
self.image.animationRepeatCount = 0; // 0 = loops forever 动画重复次数
[self.image startAnimating];
-
作用在layer上的动画CAAnimation
caanimation不会改变对应的属性,只是视觉效果上有变化
CABaseAnimation
// 1. 创建核心动画
CABasicAnimation *anima = [CABasicAnimation animation] ;
// 1.1设置动画类型
// anima.keyPath = @"transform.translation.x";
anima.keyPath = @"transform.scale";
// 1.2 设置动画执行完毕之后不删除动画
anima.removedOnCompletion = NO;
// 1.3 设置保存动画的最新状态
anima.fillMode = kCAFillModeForwards;
// 1.4设置动画时间
anima.duration = 1;
// 1.5如何动画
// anima.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(0, 100, 1)];
// anima.toValue = @(100);
anima.toValue = @(1.5);
// 2.添加核心动画到Layer
[self.myLayer addAnimation:anima forKey:nil];
// 1. 创建核心动画
CABasicAnimation *anima = [CABasicAnimation animation] ;
// 1.1告诉系统要执行什么样的动画
anima.keyPath = @"position";
// 设置通过动画将layer从哪
anima.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
// 到哪(到指定的位置)
anima.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 300)];
// 在当前位置的基础上增加多少
// anima.byValue = [NSValue valueWithCGPoint:CGPointMake(0, 300)];
// 设置动画时间
anima.duration = 5;
// 1.2 设置动画执行完毕之后不删除动画
anima.removedOnCompletion = NO;
// 1.3 设置保存动画的最新状态
anima.fillMode = kCAFillModeForwards;
// 2.添加核心动画到Layer
[self.myLayer addAnimation:anima forKey:nil];
step1:准备演员(CALayer初始化)
CALayer *scaleLayer = [[CALayer alloc] init];
scaleLayer.backgroundColor = [UIColor blueColor].CGColor;
scaleLayer.frame = CGRectMake(60, 20 + kYOffset, 50, 50);
scaleLayer.cornerRadius = 10;
[self.view.layer addSublayer:scaleLayer];
step2: 准备剧本(配置CABasicAnimation)
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale”];
//keyPath不能填错,有特定被选值
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleAnimation.autoreverses = YES;
scaleAnimation.fillMode = kCAFillModeForwards;
scaleAnimation.removedOnCompletion = NO;
scaleAnimation.repeatCount = MAXFLOAT;
scaleAnimation.duration = 0.8;
step3: 开演
[scaleLayer addAnimation:scaleAnimation forKey:@"scaleAnimation”];
-
keyPath: 决定基础动画的类型,该值不能随便取,一旦取错就达不到想要的效果。要改变位置就取position,要改变透明度就取opacity,要等比例缩放就取transform.scale...更多key请看下面的表1,要尽量能记住这些内容
-
fromValue: 动画的起始状态值,虽然iOS文档给出的类型是id,不过这里应该传NSValue对象,比如NSNumber(NSNubmer继承自NSValue)。其具体含义
-
autoreverse: 当动画执行到toValue指定的状态时是从toValue的状态逆回去,还是直接跳到fromValue的状态再执行一遍
-
fileMode: fillMode的作用就是决定当前对象过了非active时间段的行为. 非active时间段是指动画开始之前以及动画结束之后。如果是一个动画CAAnimation,则需要将其removedOnCompletion设置为NO,要不然fillMode不起作用. 下面来讲各个fillMode的意义:
-
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
-
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
-
kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态。因为有可能出现fromValue不是目前layer的初始状态的情况,如果fromValue就是layer当前的状态,则这个参数就没太大意义。
-
kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态.
CABasicAnimation的常用keypath
CAKeyFrameAnimation
圆形轨迹运动的例子
// 1.创建核心动画
CAKeyframeAnimation *keyAnima = [CAKeyframeAnimation animation];
// 1.1告诉系统执行什么动画
keyAnima.keyPath = @"position";
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 100, 200, 200));
keyAnima.path = path;
CGPathRelease(path);
// 1.2保存执行完之后的状态
// 1.2.1执行完之后不删除动画
keyAnima.removedOnCompletion = NO;
// 1.2.2执行完之后保存最新的状态
keyAnima.fillMode = kCAFillModeForwards;
// 1.3设置动画时间
keyAnima.duration = 2;
// 2.观察动画什么时候开始执行, 以及什么时候执行完毕
keyAnima.delegate = self;
// 3.添加核心动画
[self.customView.layer addAnimation:keyAnima forKey:@"abc"];
三角形轨迹运动
// 1.创建核心动画
CAKeyframeAnimation *keyAnima = [CAKeyframeAnimation animation];
// 1.1告诉系统执行什么动画
keyAnima.keyPath = @"position";
CGMutablePathRef path = CGPathCreateMutable();
CGPoint lines[] = {
CGPointMake(50, 50),
CGPointMake(300, 50),
CGPointMake(300, 200),
CGPointMake(50, 50)
};
const CGAffineTransform trans[] = {
CGAffineTransformIdentity
};
NSInteger size = sizeof(lines)/sizeof(lines[0]);
CGPathAddLines(path, trans, lines, size);
// CGPathMoveToPoint(path, nil, 50, 50);
// CGPathAddLineToPoint(path, nil, 300, 50);
// CGPathAddLineToPoint(path, nil, 300, 200);
// CGPathCloseSubpath(path);
keyAnima.path = path;
CGPathRelease(path);
// 1.2保存执行完之后的状态
// 1.2.1执行完之后不删除动画
keyAnima.removedOnCompletion = NO;
// 1.2.2执行完之后保存最新的状态
keyAnima.fillMode = kCAFillModeForwards;
// 1.3设置动画时间
keyAnima.duration = 2;
// 2.观察动画什么时候开始执行, 以及什么时候执行完毕
keyAnima.delegate = self;
// 3.添加核心动画
[self.animationLayer addAnimation:keyAnima forKey:@"abc"];
代理方法
- (void)animationDidStart:(CAAnimation *)anim
{
NSLog(@"animationDidStart");
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
NSLog(@"animationDidStop");
}
提前结束动画
// 停止动画
[self.customView.layer removeAnimationForKey:@"abc"];
图标抖动的例子
#define angle2Radian(angle) ((angle) / 180.0 * M_PI)
// 1.创建核心动画
CAKeyframeAnimation *keyAnima = [CAKeyframeAnimation animation];
keyAnima.keyPath = @"transform.rotation";
// 度数 / 180 * M_PI
keyAnima.values = @[@(-angle2Radian(4)), @(angle2Radian(4)), @(-angle2Radian(4))];
keyAnima.removedOnCompletion = NO;
keyAnima.fillMode = kCAFillModeForwards;
keyAnima.duration = 0.1;
// 设置动画重复的次数
keyAnima.repeatCount = MAXFLOAT;
// 2.添加核心动画
[self.iconView.layer addAnimation:keyAnima forKey:nil];
CAAnimationGroup
多种动画效果合并
缩放动画
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleAnimation.autoreverses = YES;
scaleAnimation.repeatCount = MAXFLOAT;
scaleAnimation.duration = 0.8;
移动动画
CABasicAnimation *moveAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
moveAnimation.fromValue = [NSValue valueWithCGPoint:groupLayer.position];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(320 - 80, groupLayer.position.y)];
moveAnimation.autoreverses = YES;
moveAnimation.repeatCount = MAXFLOAT;
moveAnimation.duration = 2;
旋转动画
CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
rotateAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotateAnimation.toValue = [NSNumber numberWithFloat:6.0 * M_PI];
rotateAnimation.autoreverses = YES;
rotateAnimation.repeatCount = MAXFLOAT;
rotateAnimation.duration = 2;
大剧本
CAAnimationGroup *groupAnnimation = [CAAnimationGroup animation];
groupAnnimation.duration = 2;
groupAnnimation.autoreverses = YES;
groupAnnimation.animations = @[moveAnimation, scaleAnimation, rotateAnimation];
groupAnnimation.repeatCount = MAXFLOAT;
开演
[groupLayer addAnimation:groupAnnimation forKey:@"groupAnnimation”];
CATransition
转场动画
self.index++;
if (self.index >7) {
self.index = 1;
}
NSString *imageName = [NSString stringWithFormat:@"%d.jpg", self.index];
UIImage *newImage = [UIImage imageNamed:imageName];
self.iconView.image = newImage;
// 1.创建核心动画
CATransition *ca = [CATransition animation];
// 1.1动画过渡类型
ca.type = @"fade";//fade ,cube,reveal,push,moveIn
// 1.2动画过渡方向
ca.subtype = kCATransitionFromRight;
// 1.3动画起点(在整体动画的百分比)
// ca.startProgress = 0.5;
// ca.endProgress = 0.5;
// 动画时间
ca.duration = 1;
// 2.添加核心动画
[self.iconView.layer addAnimation:ca forKey:nil];
隐式动画
UIView内部都有一个CALayer(root layer),其他手动创建的CALayer对象,都有隐式动画。
对非root layer的属性(bounds,backgroundColor,position)做改变时,会有默认的动画效果。
position 和 anchorPoint
position (CALayer在父layer的位置)
anchorPoint
(0,0) 左上角
(0.5,0.5)中心点
CALayer *layer=[CALayer layer];
layer.backgroundColor=[UIColor yellowColor].CGColor;
layer.bounds=CGRectMake( 0, 0, 100, 100);
layer.position=CGPointMake(100, 100);
layer.anchorPoint=CGPointMake(1, 0.5);
[self.view.layer addSublayer:layer];
self.layer=layer;
//target action
self.layer.backgroundColor=[UIColor redColor].CGColor;
UIViewController转场效果
push的动画
动画效果演示
渐变出现,渐变消失
//将UILabel的位置放在视图上方
UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(100,-100, 100, 100)];
label.backgroundColor=[UIColor yellowColor];
label.alpha=0;
[self.view addSubview:label];
//将视图的下移进入视图,并逐渐增大alpha
[UIView animateWithDuration:2 animations:^{
label.alpha=1;
label.transform=CGAffineTransformTranslate(label.transform, 0, 200);
} completion:^(BOOL finished){
label.alpha=1;
}];
//延时进行第二次动画处理,逐渐减少alpha
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:2 animations:^{
label.alpha=0;
} completion:^(BOOL finished){
}];
});
几种常见的动画效果的实现
https://my.oschina.net/u/2360054/blog/785388
//TODO:
1整理成知识点
2完善git代码仓库
问题1,如何对一个UIView,编写一个CABasicAnimation 让视图不停地旋转
问题2,如何编写一个CAKeyFrameAnimation实现沿着路径运动
问题3,如何编写一个组合动画
问题4,UIViewController转场动画
问题5,自定义present的动画
问题6,
参考资料
http://www.cocoachina.com/ios/20160526/16456.html
来源:oschina
链接:https://my.oschina.net/u/2360054/blog/495634