iOS动画

实现动画方法有很多种:图片动画最简单的是用数组放多张图片,用UIImageView展示,但耗内存。UIView动画(包含转场动画)。可以用layer,可以配合贝塞尔曲线,贝塞尔曲线是画图的,动画效果都是通过CAAnimation类的子类(CAAnimation是抽象类)来完成的。CAAnimation类的子类包括了CAAnimationGroup,CAPropertyAnimation,CATransition,而CAPropertyAniamtion(同为抽象类)也衍生了CABasicAnimation和CAKeyframeAnimation。用UIView的animation实现的动画本质上也是通过CALayer来实现的

UIView动画 animateWithDuration方法

//下划线位置变换
    [UIView animateWithDuration:0.25f animations:^{
        
        self.lineView.frame = CGRectMake(((screenWidth/self.titleArr.count)-40)/2+(screenWidth/self.titleArr.count)*index, 50-4, 40, 3);
    }];
[self.myTableView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
    
    //如果想要约束变换之后实现动画效果,则需要执行如下操作
    //layoutIfNeeded   告知页面布局立刻更新
    [UIView animateWithDuration:0.3 animations:^{
        [self.view layoutIfNeeded];   //更新界面
    }];
//单视图动画
    [UIView transitionWithView:sender duration:2.0f options:UIViewAnimationOptionTransitionFlipFromRight animations:nil completion:^(BOOL finished) {
        [self.navigationController pushViewController:vc animated:YES];
    }];
//双视图转场动画   transitionFromView
- (void)onAnimationBtn:(UIButton *)sender {
    CFFAnimationViewController *vc = [CFFAnimationViewController new];
//    [self.navigationController pushViewController:vc animated:YES];
    
    //双视图转场动画
    [UIView transitionFromView:self.view toView:vc.view duration:2.0f options:UIViewAnimationOptionTransitionFlipFromRight completion:nil];
}

UIView动画 beginAnimations commitAnimations

 // 从beginAnimations到commitAnimations完成一次完成的动画    layoutIfNeeded必须要的,不然动画执行无效
        [UIView beginAnimations:nil context:nil]; //开始动画
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        [UIView setAnimationDuration:0.3f];  //动画时长
        
        [self.photoView mas_updateConstraints:^(MASConstraintMaker *make) {
            make.left.right.equalTo(self.view);
            make.bottom.equalTo(self.view.mas_bottom);
            make.height.mas_equalTo(@80);
        }];
        
        [self.bottomView mas_updateConstraints:^(MASConstraintMaker *make) {
            make.right.left.equalTo(self.view);
            make.bottom.equalTo(self.view).offset(-80);
            make.height.mas_equalTo(@50);
        }];
        self.bottomConstraint.constant = 50+80;
        [self.view layoutIfNeeded];
        [UIView commitAnimations];  //提交动画

贝塞尔曲线

//圆形循环
- (void)dongHua {
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(60 / 2.f, 60 / 2.f)
                                                        radius:60 / 2.f
                                                    startAngle:0
                                                      endAngle:M_PI * 2
                                                     clockwise:YES];
    
    CAShapeLayer *shapelayer = [CAShapeLayer layer];
    shapelayer.frame = CGRectMake(100, 100, 60, 60);
    shapelayer.path = path.CGPath;
    shapelayer.lineWidth = 4.0f;
    shapelayer.lineCap = kCALineCapSquare;  //边缘线类型
    shapelayer.fillColor = [UIColor clearColor].CGColor;
    shapelayer.strokeColor = [UIColor orangeColor].CGColor;
    shapelayer.strokeStart = 0.0f;
    shapelayer.strokeEnd = 0.1f;
    [self.view.layer addSublayer:shapelayer];
    
    CABasicAnimation *basicAnmation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    basicAnmation.duration = 2.0;
    basicAnmation.repeatCount = 1;
    basicAnmation.fromValue = [NSNumber numberWithInt:0.0f];
    basicAnmation.toValue = [NSNumber numberWithInt:1.0f];
    basicAnmation.removedOnCompletion = NO;
    basicAnmation.fillMode = kCAFillModeForwards;
    [shapelayer addAnimation:basicAnmation forKey:nil];
}

核心动画

/*
 CAAnimation是所有动画类的父类,但是它不能直接使用,应该使用它的子类。
 能用的动画类只有4个子类:CABasicAnimation、CAKeyframeAnimation、CATransition、CAAnimationGroup
 */
- (void)animationLabelView {
    _animationLab = [[UILabel alloc] initWithFrame:CGRectMake(10, 40, 60, 30)];
    _animationLab.textAlignment = NSTextAlignmentCenter;
    _animationLab.text = @"动画";
    _animationLab.backgroundColor = [UIColor orangeColor];
    _animationLab.textColor = [UIColor whiteColor];
    [self.view addSubview:_animationLab];
    
    //闪烁动画
    //    [_animationLab.layer addAnimation:[self opacityForever_Animation:0.5f] forKey:nil];
    
    //纵向横向移动
    //    [_animationLab.layer addAnimation:[self movex:1.0f x:[NSNumber numberWithFloat:200.0f]] forKey:nil];
    
    //缩放
    //    [_animationLab.layer addAnimation:[self scale:[NSNumber numberWithFloat:1.0f] orgin:[NSNumber numberWithFloat:0.3f] durTimes:0.5f Rep:MAXFLOAT] forKey:nil];
    
    //组合
    //    NSArray *animationArray = [NSArray arrayWithObjects:[self opacityForever_Animation:0.5f],[self movex:1.0f x:[NSNumber numberWithFloat:200.0f]],[self scale:[NSNumber numberWithFloat:1.0f] orgin:[NSNumber numberWithFloat:0.3f] durTimes:0.5f Rep:MAXFLOAT], nil];
    //    [_animationLab.layer addAnimation:[self groupAnimation:animationArray durTimes:1.0f Rep:MAXFLOAT] forKey:nil];
    
    
    //路径
    //    CGMutablePathRef pathRef = CGPathCreateMutable();
    //    CGPathMoveToPoint(pathRef, nil, 30, 77);  //
    //    CGPathAddCurveToPoint(pathRef, nil, 50, 50, 60, 200, 200, 200);
    //    [_animationLab.layer addAnimation:[self keyframeAnimation:pathRef durTimes:1.0f Rep:MAXFLOAT] forKey:nil];
    
    
    //旋转
    //    [_animationLab.layer addAnimation:[self rotation:2 degree:kRadianToDegrees(180) direction:1 repeatCount:MAXFLOAT] forKey:nil];
    
    
    
    //绕y旋转
//    [_animationLab.layer addAnimation:[self rotationFromYWithDur:1.0f] forKey:nil];
    //绕y旋转   方法一:旋转时过渡平滑
//    [_animationLab.layer addAnimation:[self rotationFromYWithDur:1.0f] forKey:@"rotationAnimation"];
    //UIView动画
//    方法二:如同方法一,但是过渡时效果没有方法一的舒服,感觉差那么一点
    //@param duration 持续时间
    //@param delay  延时时间
    //@param options  方式
    [UIView animateWithDuration:1.0
                          delay:0
                        options:UIViewAnimationOptionRepeat
                     animations:^{
                         //你想绕哪个轴哪个轴就为 1,其中的参数(角度, x, y, z)
                         _animationLab.layer.transform=CATransform3DMakeRotation(M_PI, 0, 1, 0);
                     }
                     completion:^(BOOL finished) {
                         //你想绕哪个轴哪个轴就为 1,其中的参数(角度, x, y, z)
                         _animationLab.layer.transform=CATransform3DMakeRotation(M_PI, 0, 1, 0);
                     }];
}

#pragma mark - 永久闪烁的动画
- (CABasicAnimation *)opacityForever_Animation:(float)time {
    //透明度
    CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; //必须是opacity(不透明度)
    
    baseAnimation.fromValue = [NSNumber numberWithFloat:1.0f];
    baseAnimation.toValue = [NSNumber numberWithFloat:0.0f];  //透明度
    baseAnimation.fillMode = kCAFillModeForwards;  //fillMode的作用就是决定当前对象过了非active时间段的行为. 比如动画开始之前,动画结束之后。如果是一个动画CAAnimation,则需要将其removedOnCompletion设置为NO,要不然fillMode不起作用.kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
    /*
     kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
    kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
    kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始.你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态
    kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态.
     */
    baseAnimation.autoreverses = YES;   //动画结束时是否进行逆反
    baseAnimation.duration = time;
    baseAnimation.repeatCount = MAXFLOAT;
    baseAnimation.removedOnCompletion = NO;    //YES就是动画完成后自动变回原样,动画完成后是否移除动画,.默认为YES.此属性为YES时, fillMode不可用
    baseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];  //没有的话,是均匀的动画   timingFunction速度控制函数
    
    
    
    //缩放
//    CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];  //transform.scale(变换 缩放)
//    baseAnimation.fromValue = [NSNumber numberWithFloat:1.0f];
//    baseAnimation.toValue = [NSNumber numberWithFloat:0.0f];  //缩放值
//    baseAnimation.autoreverses = YES;     //动画结束时是否执行逆动画
//    baseAnimation.duration = time;
//    baseAnimation.repeatCount = MAXFLOAT;    //是否动画永远持续

    return baseAnimation;
}

#pragma mark - 纵向、横向移动
- (CABasicAnimation *)movex:(float)time x:(NSNumber *)x {
    CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"]; //.y的话,就会向下移
    baseAnimation.toValue = x;
    baseAnimation.duration = time;
    baseAnimation.repeatCount = MAXFLOAT;
    baseAnimation.fillMode = kCAFillModeForwards;
    baseAnimation.removedOnCompletion = NO;  //为YES,就会又回到原位置,动画完成后是否移除动画,.默认为YES.此属性为YES时, fillMode不可用
    
    return baseAnimation;
}

#pragma mark - 缩放
-(CABasicAnimation *)scale:(NSNumber *)Multiple orgin:(NSNumber *)orginMultiple durTimes:(float)time Rep:(float)repertTimes {
    CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    baseAnimation.fromValue = Multiple;
    baseAnimation.toValue = orginMultiple;
    baseAnimation.duration = time;   //不设置,会有个默认的缩放时间
    baseAnimation.repeatCount = repertTimes;
    baseAnimation.autoreverses = YES;
    baseAnimation.fillMode = kCAFillModeForwards;
    baseAnimation.removedOnCompletion = NO;
    
    return baseAnimation;
}

#pragma mark - 组合动画
-(CAAnimationGroup *)groupAnimation:(NSArray *)animationArray durTimes:(float)time Rep:(float)repeatTimes {
    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    animationGroup.animations = animationArray;
    animationGroup.duration = time;
    animationGroup.repeatCount = repeatTimes;
    animationGroup.removedOnCompletion = NO;
    animationGroup.fillMode = kCAFillModeForwards;
    
    return animationGroup;
}

#pragma mark - 路径动画
-(CAKeyframeAnimation *)keyframeAnimation:(CGMutablePathRef)path durTimes:(float)time Rep:(float)repeatTimes {
    CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    keyFrameAnimation.path = path;
    keyFrameAnimation.duration = time;
    keyFrameAnimation.repeatCount = repeatTimes;
    keyFrameAnimation.autoreverses = YES;
    keyFrameAnimation.removedOnCompletion = NO;
    keyFrameAnimation.fillMode = kCAFillModeForwards;
    keyFrameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];  //没有设置,就是匀速
    
    return keyFrameAnimation;
}

#pragma mark - 旋转
-(CABasicAnimation *)rotation:(float)dur degree:(float)degree direction:(int)direction repeatCount:(int)repeatCount {
    CATransform3D transform3D = CATransform3DMakeRotation(degree, 0, 0, direction);
    CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    baseAnimation.toValue = [NSValue valueWithCATransform3D:transform3D];
    baseAnimation.duration = dur;
    baseAnimation.repeatCount = repeatCount;
    baseAnimation.autoreverses = NO;   //动画结束时是否进行逆动画
    baseAnimation.fillMode = kCAFillModeForwards;
    baseAnimation.cumulative = NO;  //指定动画是否为累加效果,默认为NO
//    baseAnimation.delegate = self;
    
    return baseAnimation;
}

//沿y旋转
//- (CABasicAnimation *)rotationFromYWithDur:(float)duration {
//    CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
//    baseAnimation.duration = duration;
//    baseAnimation.repeatCount = HUGE_VALF;  //重复不停
//    baseAnimation.fromValue = [NSNumber numberWithFloat:0];
//    baseAnimation.toValue = [NSNumber numberWithFloat:M_PI*2]; //结束时的角度
//    baseAnimation.autoreverses = NO;
//    //动画终了后不返回初始状态
//    baseAnimation.removedOnCompletion = NO;
//    baseAnimation.fillMode = kCAFillModeForwards;
//
//    return baseAnimation;
//}

//沿y旋转
- (CABasicAnimation *)rotationFromYWithDur:(float)duration {
    CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    baseAnimation.duration = duration;
    baseAnimation.repeatCount = HUGE_VALF;  //重复不停
//    baseAnimation.toValue = [NSNumber numberWithFloat:M_PI];
    baseAnimation.toValue = [NSNumber numberWithFloat:M_PI*2];
    baseAnimation.autoreverses = NO;
    //动画终了后不返回初始状态
    baseAnimation.removedOnCompletion = NO;
    baseAnimation.fillMode = kCAFillModeForwards;
    
    return baseAnimation;
}

//CATransition

- (void)animationImageView {
    _animationIV = [[UIImageView alloc] initWithFrame:CGRectMake(10, 120, 100, 100)];
    _animationIV.image = [UIImage imageNamed:@"Yosemite00"];
    [self.view addSubview:_animationIV];
    
    UIButton *nextBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    nextBtn.frame = CGRectMake(80, 240, 40, 20);
    nextBtn.titleLabel.font = [UIFont systemFontOfSize:12];
    [nextBtn setTitle:@"next" forState:UIControlStateNormal];
    [nextBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];
    [nextBtn addTarget:self action:@selector(onNextBtn:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:nextBtn];
}
//转场动画: CATransition 单视图转场  双视图转场
- (void)onNextBtn:(id)sender {
    self.index++;
    if (self.index >= 5) {
        self.index=0;
    }
    _animationIV.image = [UIImage imageNamed:[NSString stringWithFormat:@"Yosemite0%ld",(long)self.index]];
    
    //1.创建核心动画
    CATransition *caAnmation = [CATransition animation];
    //1.1告诉要执行什么动画
    //1.2设置过度效果
    caAnmation.type = @"cube";
    //1.3设置动画的过度方向(向右)
    caAnmation.subtype = kCATransitionFromRight;
    //1.4设置动画的时间
    caAnmation.duration = 2.0f;
    //1.5设置动画的起点
    caAnmation.startProgress = 0.5f;
    //1.6设置动画的终点
//    caAnmation.endProgress = 0.0f;
    
    //2.添加动画
    [self.animationIV.layer addAnimation:caAnmation forKey:nil];
    
}

demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容

  • 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你...
    Yiart阅读 3,819评论 3 34
  • 在iOS实际开发中常用的动画无非是以下四种:UIView动画,核心动画,帧动画,自定义转场动画。 1.UIView...
    请叫我周小帅阅读 3,101评论 1 23
  • 目录 ** UIView 动画 ** ** Core Animation ** ** FaceBook POP动画...
    方向_4d0d阅读 1,603评论 0 3
  • 显式动画 显式动画,它能够对一些属性做指定的自定义动画,或者创建非线性动画,比如沿着任意一条曲线移动。 属性动画 ...
    清风沐沐阅读 1,941评论 1 5
  • 我真心的觉得每本书都很厉害。 总有人问我,你最喜欢哪本书,你最喜欢哪个作者,你最喜欢哪种体裁,你最喜欢哪种修辞手法...
    鹰鸣神舞阅读 203评论 0 2