实现动画方法有很多种:图片动画最简单的是用数组放多张图片,用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