facebook的动画框架pop:https://github.com/facebook/pop
or
核心动画类有以下分类:
- 提供显示内容的图层类。
- 动画和计时类。
- 布局和约束类。
- 事务类,在原子更新的时候组合图层类。
核心动画的基础类包含在Quartz核心框架(Quartz Core framework)里面,虽然它的其他图层类在其他框架里面定义。下图显示了核心动画的类层次结构。
图 1 Core Animation 类结构
1.1.1 图层类(Layer Classes)
图层类是核心动画的核心基础,它提供了一套抽象的概念(假如你使用过NSView或者UIView的话,你一定会对它很熟悉)。CALayer是整个图层类的基础,它是所有核心动画图层类的父类。
和视图类(NSView或UIView)一样,CALayer有自己的父图层类,同时也拥有自己子图层类的集合,它们构成了一个图层树的层次结构。图层绘制类似视图一样自底向上,并指定其几何形状相对他们superlayer,创建一个相对的局部坐标系。然而图层类通过合并变换矩阵允许你旋转、偏移、拉伸对应的图层内容。具体内容将会在后面“图层(Layer)的几何和变换”部分介绍。
CALayer从Application Kit 和Cocoa Touch的视图类分离出来,因为没有必要为了显示内容而继承CALayer类。因为CALayer类的内容显示可以通过以下方法提供:
- 可以直接或者委托的方式把图层的内容属性设置为Core Graphics image。
- 提供直接绘制到一个Core Graphics image上下文委托。
- 设置所有图层所具有的可视化样式属性,比如背景颜色、不透明属性、蒙版等。
Mac OS X应用同样可以通过核心图像滤镜来访问它的可视化样式属性。
继承CALayer并通过封装方法实现以上任何技术。
“提供图层内容”描述了提供内容层可用方法。可视化样式样式属性和它们的顺序将会在 “图层样式属性”部分详细介绍。
除了CALayer类,核心动画类同时提供了显示其他内容的类。这些类在Mac OS X 和 iOS上有细微的差别,以下类在Mac OS X和iOS上都可用:
CAScrollLayer
是CALayer的子类,简化显示图层的一部分内容。CAScrollLayer对象的滚动区域的范围在它的子图层里面定义。CAScrollLaye不提供键盘或鼠标事件处理,也不提供可见的滚动条。CATextLayer
可以方便的从字符串或字符串的内容创建一个图层类的内容。CATiledLayer
允许递增的显示大而复杂的图片。
Mac OS X 提供如下额外的类:
CAOpenGLLayer
提供了一个OpenGL渲染环境。你必须继承这个类来使用OpenGL提供的内容。内容可以是静态的,或可随着时间的推移更新。QCCompositionLayer
(由Quartz框架提供)可以把Quartz合成的内容动画显示。QTMovieLayer and QTCaptureLayer
(QTKit框架提供)提供播放QuickTime影片和视频直播。
iOS 提供如下额外的类:
CAEAGLLayer
提供了一个OpenGLES渲染环境。
CALayer的类引入键-值编码兼容的容器类概念,也就是说一个类可以使用键 - 值编码的方法存储任意值,而无需创建一个子类。CALayer的还扩展了NSKeyValueCoding的非正式协议,加入默认键值和额外的结构类型的自动对象包装(CGPoint,CGSize,CGRect,CGAffineTransform和CATransform3D)的支持,并提供许多这些结构的关键路径领域的访问。
CALayer同时管理与层关联的动画和行为,。图层接受层树的插入和删除层动作,修改层的属性,或者明确的开发请求。这些行为通常会导致动画发生。见“动画”和“图层操作”的更多信息。
1.1.2 动画和计时类
图层的很多可视化属性是可以隐式动画的。通过简单的改变图层的可动画显示的属性,可以让图层现有属性从当前值动画渐变到新的属性值。例如设置图层的hidden属性为YES将会触发动画使层逐渐淡出。大多数动画属性拥有自己关联的默认动画,你可以轻松地定制和替换。我们将会在后面“动画属性”部分列出一个完整的动画属性列表和它们相应的默认动画。动画的属性也可以显式动画。要显式动画的属性,你需要创建核心动画动画类的一个实例,并指定所需的视觉效果。显式动画不会改变该属性的值,它只是用于动画显示。
核心动画的动画类使用基本的动画和关键帧动画把图层的内容和选取的属性动画的显示出来。所有核心动画的动画类都是从CAAnimation类继承而来。CAAnimation实现了CAMediaTiming协议,提供了动画的持续时间,速度,和重复计数。CAAnimation也实现了CAAction协议。该协议为图层触发一个动画动作提供了提供标准化响应。
动画类同时定义了一个使用贝塞尔曲线来描述动画改变的时间函数。例如,一个匀速时间函数(linear timing function)在动画的整个生命周期里面一直保持速度不变,而渐缓时间函数(ease-out timing function)则在动画接近其生命周期的时候减慢速度。
核心动画额外提供了一系列抽象的和细化的动画类,比如:
CATransition
提供了一个图层变化的过渡效果,它能影响图层的整个内容。动画进行的时候淡入淡出(fade)、推(push)、显露(reveal)图层的内容。这些过渡效果可以扩展到你自己定制的Core Image滤镜。
CAAnimationGroup
允许一系列动画效果组合在一起,并行显示动画。CAPropertyAnimation
是一个抽象的子类,它支持动画的显示图层的关键路径中指定的属性CABasicAnimation
简单的为图层的属性提供修改。CAKeyframeAnimation
支持关键帧动画,你可以指定的图层属性的关键路径动画,包括动画的每个阶段的价值,以及关键帧时间和计时功能的一系列值。在动画运行是,每个值被特定的插入值替代。
核心动画 和 Cocoa Animation 同时使用这些动画类。使用动画描述,是因为这些类涉及到核心动画,这些将会在Animation Types and Timing Programming Guide 有较深入的讨论。
1.1.3 布局管理器类
Application Kit的视图类相对于superlayer提供了经典的“struts and springs”定位模型。图层类兼容这个模型,同时 Mac OS X上面的核心动画提供了一套更加灵活的布局管理机制,它允许开发者自己修改布局管理器。核心动画的 CAConstraint 类是一个布局管理器,它可以指定子图层类限制于你指定的约束集合。每个约束(CAConstraint类的实例封装)描述层的几何属性(左,右,顶部或底部的边缘或水平或垂直中心)的关系,关系到其同级之一的几何属性层或superlayer。
通用的布局管理器和约束性布局管理器将会在“布局核心动画的图层”部分讨论。
1.1.4 事务管理类
图层的动画属性的每一个修改必然是事务的一个部分。CATransaction是核心动画里面负责协调多个动画原子更新显示操作。事务支持嵌套使用。
核心动画支持两种事务:隐式事务和显式事务。在图层的动画属性被一个线程修改,同时该线程下次迭代的时候自动提交该修改的时候隐式事务自动创建。显式事务发生在程序在修改动画属性之前给CATransaction发送了一个开始消息,在动画属性修改之后提交该消息。
虽然核心动画的图层和 Cocoa的视图在很大程度上没有一定的相似性,但是他们两者最大的区别是,图层不会直接渲染到屏幕上。
在模型-视图-控制器(model-view-controller)概念里面NSView和UIView是典型的视图部分,但是在核心动画里面图层是模型部分。图层封装了几何、时间、可视化属性,同时它提供了图层现实的内容,但是实际显示的过程则不是由它来完成。
每个可见的图层树由两个相应的树组成:一个是呈现树,一个是渲染树。下图显示在Mac OS X上面使用核心动画图层类显示一个图层树的例子。
图 1 Core Animation 渲染架构
图层树包含每一层的对象模型值。他们就是你设定的图层的属性值。
呈现树包含了当前动画发生时候将要显示的值,例如你要给图层背景颜色设置新的值的时候,它会立即修改图层树里面相应的值。但是在呈现树里面背景颜色值在将要显示给用户的时候才被更新为新值。
渲染树在渲染图层的时候使用呈现树的值。渲染树负责执行独立于应用活动的复杂操作。渲染由一个单独的进程或线程来执行,使其对应用程序的运行循环影响最小。
eAnimation编程指南=================
1.(CATransaction :NSObject)继承自NSObject的动画;
2.UIView的动画;
3.继承自CAAnimation的动画;分为CAPropertyAnimation(属性动画,包括CABasicAnimation---基础动画,基础又包括
CASpringAnimation;CAKeyframeAnimation---帧动画;)
CAAnimationGroup--组动画;
CATransition--转场动画;
所有核心动画和特效都是基于CAAnimation,而CAAnimation是作用于CALayer的.所以把动画添加到layer上.
有关动画的总结
1.隐式动画CATransaction
非rootLayer,即手动创建的layer都包含隐式动画;(position,bounds,backgroundColor,)
UITouch * touch = touches.anyObject;
//获取触摸点
CGPoint point = [touch locationInView:touch.view];
//改变myLayer的位置
//修改动画属性
[CATransaction begin];
//设置动画为否
[CATransaction setDisableActions:YES];
//修改动画时间
// [CATransaction setAnimationDuration:2];
self.myLayer.position = point;//设置的属性要放在提交之前
//提交
[CATransactioncommit];
=====================================================================
/** CABasicAnimation
*
*
* @brief 便利构造函数 animationWithKeyPath: KeyPath需要一个字符串类型的参数,实际上是一个
* 键-值编码协议的扩展,参数必须是CALayer的某一项属性,你的代码会对应的去改变该属性的效果
* 具体可以填写什么请参考上面的URL,切勿乱填!
* 例如这里填写的是 @"transform.rotation.z"意思就是围绕z轴旋转,旋转的单位是弧度.
* 这个动画的效果是把view旋转到最小,再旋转回来.
* 你也可以填写@"opacity"去修改透明度...以此类推.修改layer的属性,可以用这个类.
*
* @param toValue 动画结束的值.CABasicAnimation自己只有三个属性(都很重要)(其他属性是继承来的),分别为:
* fromValue(开始值), toValue(结束值), byValue(偏移值),
! 这三个属性最多只能同时设置两个;
* 他们之间的关系如下:
* 如果同时设置了fromValue和toValue,那么动画就会从fromValue过渡到toValue;
* 如果同时设置了fromValue和byValue,那么动画就会从fromValue过渡到fromValue + byValue;
* 如果同时设置了byValue 和toValue,那么动画就会从toValue - byValue过渡到toValue;
*
* 如果只设置了fromValue,那么动画就会从fromValue过渡到当前的value;
* 如果只设置了toValue ,那么动画就会从当前的value过渡到toValue;
* 如果只设置了byValue ,那么动画就会从从当前的value过渡到当前value + byValue.
*
* 可以这么理解,当你设置了三个中的一个或多个,系统就会根据以上规则使用插值算法计算出一个时间差并
* 同时开启一个Timer.Timer的间隔也就是这个时间差,通过这个Timer去不停地刷新keyPath的值.
! 而实际上,keyPath的值(layer的属性)在动画运行这一过程中,是没有任何变化的,它只是调用了GPU去
* 完成这些显示效果而已.
* 在这个动画里,是设置了要旋转到的弧度,根据以上规则,动画将会从它当前的弧度专旋转到我设置的弧度.
*
* @param duration 动画持续时间
*
* @param timingFunction 动画起点和终点之间的插值计算,也就是说它决定了动画运行的节奏,是快还是慢,还是先快后慢...
*/
/** CAAnimationGroup
*
* @brief 顾名思义,这是一个动画组,它允许多个动画组合在一起并行显示.比如这里设置了两个动画,
* 把他们加在动画组里,一起显示.例如你有几个动画,在动画执行的过程中需要同时修改动画的某些属性,
* 这时候就可以使用CAAnimationGroup.
*
* @param duration 动画持续时间,值得一提的是,如果添加到group里的子动画不设置此属性,group里的duration会统一
* 设置动画(包括子动画)的duration属性;但是如果子动画设置了duration属性,那么group的duration属性
* 的值不应该小于每个子动画中duration属性的值,否则会造成子动画显示不全就停止了动画.
*
* @param autoreverses 动画完成后自动重新开始,默认为NO.
*
* @param repeatCount 动画重复次数,默认为0.
*
* @param animations 动画组(数组类型),把需要同时运行的动画加到这个数组里.
*
* @note addAnimation:forKey 这个方法的forKey参数是一个字符串,这个字符串可以随意设置.
*
* @note 如果你需要在动画group执行结束后保存动画效果的话,设置 fillMode 属性,并且把
* removedOnCompletion 设置为NO;
*/
//旋转
-(void)rotateAnimate{
//1.创建动画对象
CABasicAnimation * basic = [CABasicAnimation animation];
//2.设置属性 (默认绕着z轴旋转)
basic.keyPath =@"transform.rotation";
//2.1 设置结束值
basic.toValue = @(M_PI_4);
//2.2 设置动画时间
basic.duration = 2;
//设置动画结束后保持当前状态
basic.removedOnCompletion =NO;
basic.fillMode =kCAFillModeForwards;
//3.添加到要作用的layer上
[self.treeView.layer addAnimation:basic forKey:nil];
}
//缩放
-(void)scaleAnimate{
//基本动画 ---- 缩放
//1.创建动画对象
CABasicAnimation * basicAnimation = [CABasicAnimation animation];
//2.设置动画属性 (缩放)
basicAnimation.keyPath = @"transform.scale";
//2.1设置结束值
// basicAnimation.toValue = @(0.5);
basicAnimation.byValue = @(0.5);
//设置动画结束不要删除
basicAnimation.removedOnCompletion = NO;
//保持当前状态
basicAnimation.fillMode =kCAFillModeForwards;
//3.把动画添加到要做用的layer上, * forKey 可以是任意字符串.
[self.treeView.layer addAnimation:basicAnimation forKey:nil];
}
//平移动
-(void)translateAnimate{
//1.创建基本动画的对象
CABasicAnimation * basicAnimation = [CABasicAnimation animation];
//2.设置动画对象的属性 (平移)
basicAnimation.keyPath = @"position";//或者
basicAnimation.keyPath=@"transform.translation";
//2.1设置起始值
// basicAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(100, 200)];
//2.2设置结束值
basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(300,400)];
// fromValue--------------起始值;
// toValue----------------移动到多少;
// byValue---------------- 移动了多少
//2.3 设置动画时间
basicAnimation.duration = 3;
//设置代理 (隐式代理)
// basicAnimation.delegate = self;
//动画结束后不要删除
basicAnimation.removedOnCompletion = NO;
//保持当前状态
basicAnimation.fillMode =kCAFillModeForwards;
//3.把动画添加到要作用的layer上
[self.treeView.layer addAnimation:basicAnimation forKey:nil];
}
//关键帧动画
-(void)keyFrameANimate{
//关键帧动画
//1.创建动画对象
CAKeyframeAnimation * keyframeAni = [CAKeyframeAnimation animation];
//设置属性
keyframeAni.keyPath = @"position";
//2.设置属性
// NSValue * value0 = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
// NSValue * value1 = [NSValue valueWithCGPoint:CGPointMake(300, 100)];
// NSValue * value2 = [NSValue valueWithCGPoint:CGPointMake(300, 300)];
// NSValue * value3 = [NSValue valueWithCGPoint:CGPointMake(100, 300)];
// NSValue * value4 = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
NSValue * value5 = [NSValue valueWithCGPoint:CGPointMake(300, 100)];
//
// keyframeAni.values = @[value0,value1,value2,value3,value4];
//创建路径对象(如果设置了path,value就被忽略了,path只对anchorpoint和position起作用)
UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20,100,300,200)];
keyframeAni.path = path.CGPath;
//速度控制函数,控制动画的节奏
keyframeAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
//设置动画时间
keyframeAni.duration = 5;
//3.把动画对象添加到要作用的layer上
[self.treeView.layer addAnimation:keyframeAni forKey:nil];
}
****实现透明度变化的动画
//透明度动画
CABasicAnimation *showViewAnn = [CABasicAnimation animationWithKeyPath:@"opacity"];
showViewAnn.fromValue = [NSNumber numberWithFloat:1.0];
showViewAnn.toValue = [NSNumber numberWithFloat:0.0];
showViewAnn.duration = 1;
showViewAnn.fillMode = kCAFillModeForwards;
showViewAnn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
showViewAnn.removedOnCompletion = NO;
[self.grass.layer addAnimation:showViewAnn forKey:@"myShow"];
*****组动画
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 1;
group.removedOnCompletion = NO;
group.repeatCount = 1;
group.fillMode = kCAFillModeForwards;
[group setAnimations:@[keyframeAni,showViewAnn]];//数组中是两个常规动画,基础动画或者帧动画
[self.grass.layer addAnimation:group forKey:@"animationOpacity"];
//实现代理方法
- (void)animationDidStart:(CAAnimation *)anim
{
NSLog(@"start---%@",NSStringFromCGPoint(self.redLayer.position));
}
//结束动画调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
// self.redLayer.position = CGPointMake(300, 400);
NSLog(@"stop---%@",NSStringFromCGPoint(self.redLayer.position));
}
/* `calculationMode' strings. */关键帧动画的属性
@property(copy)NSString *calculationMode;
CA_EXTERN NSString * const kCAAnimationLinear//线性
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAAnimationDiscrete//分离
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAAnimationPaced//节奏(一步一步的)
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAAnimationCubic//立体的
CA_AVAILABLE_STARTING (10.7, 4.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAAnimationCubicPaced//立体的一步一步的
CA_AVAILABLE_STARTING (10.7, 4.0, 9.0, 2.0);
/* `rotationMode' strings. */关键帧动画的属性
@property(nullable,copy)NSString *rotationMode;
CA_EXTERN NSString * const kCAAnimationRotateAuto//自动旋转
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCAAnimationRotateAutoReverse//自动旋转到反转
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
4.组动画 CAAnimation
/** CAAnimationGroup
*
* @brief 顾名思义,这是一个动画组,它允许多个动画组合在一起并行显示.比如这里设置了两个动画,
* 把他们加在动画组里,一起显示.例如你有几个动画,在动画执行的过程中需要同时修改动画的某些属性,
* 这时候就可以使用CAAnimationGroup.
*
* @param duration 动画持续时间,值得一提的是,如果添加到group里的子动画不设置此属性,group里的duration会统一
* 设置动画(包括子动画)的duration属性;但是如果子动画设置了duration属性,那么group的duration属性
* 的值不应该小于每个子动画中duration属性的值,否则会造成子动画显示不全就停止了动画.
*
* @param autoreverses 动画完成后自动重新开始,默认为NO.
*
* @param repeatCount 动画重复次数,默认为0.
*
* @param animations 动画组(数组类型),把需要同时运行的动画加到这个数组里.
*
* @note addAnimation:forKey 这个方法的forKey参数是一个字符串,这个字符串可以随意设置.
*
* @note 如果你需要在动画group执行结束后保存动画效果的话,设置 fillMode 属性,并且把
* removedOnCompletion 设置为NO;
*/
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//组动画
//1.创建组动画对象
CAAnimationGroup * animationGroup = [CAAnimationGroupanimation];
//2.创建子动画
//2.1 --------------缩放动画-------------------------
CABasicAnimation * basicAni = [CABasicAnimationanimation];
//设置属性
basicAni.keyPath =@"transform.scale";
basicAni.toValue = @(0.5);
//2.1 --------------缩放动画-------------------------
//2.2 --------------旋转动画-------------------------
CABasicAnimation * rotationAni = [CABasicAnimationanimation];
rotationAni.keyPath =@"transform.rotation";
rotationAni.toValue = @(M_PI * 2 *100);
//2.2 --------------旋转动画------------------------
//2.3--------------围绕椭圆旋转---------------------
CAKeyframeAnimation * keyframeAni = [CAKeyframeAnimationanimation];
//设置属性
keyframeAni.keyPath = @"position";
UIBezierPath * path = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(20,100,300,200)];
keyframeAni.path = path.CGPath;
keyframeAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];//设置两个帧之间动画的运动的节奏
//2.3--------------围绕椭圆旋转---------------------
//3.把子动画添加到组动画中
animationGroup.animations = @[basicAni,rotationAni,keyframeAni];
//设置组动画时间
animationGroup.duration = 5;
//4.把组动画添加到要作用的layer上
[self.redLayer addAnimation:animationGroup forKey:nil];
}
//组动画
-(void)animateGroup{
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.duration =0.35f;
animationGroup.autoreverses =YES;//动画完成后自动重新开始,默认为NO.
animationGroup.repeatCount =1;//重复的次数
// animationGroup.animations =[NSArray arrayWithObjects:rotationAnimation, scaleAnimation,nil];//动画添加到组
[self.treeView.layer addAnimation:animationGroup forKey:@"animationGroup"];
}
=================
5.转场动画 CATransition
/*
//1.创建动画对象
CATransition * transition = [CATransition animation];
//2.设置动画属性
transition.type = @"rippleEffect";
// transition.duration = 2;
//判断方向
if(swipeGesture.direction == UISwipeGestureRecognizerDirectionLeft)
{
//向左滑 下一张
self.index++;
//向左滑 从右边进来
transition.subtype = kCATransitionFromRight;
}
else if (swipeGesture.direction == UISwipeGestureRecognizerDirectionRight)
{
//向右滑 上一张
self.index--;
transition.subtype = kCATransitionFromLeft;
}
if (self.index > 5)
{
self.index = 1;
}
else if (self.index < 1)
{
self.index = 5;
}
//拼接图片名字
NSString * imageName = [NSString stringWithFormat:@"%d",self.index];
self.imageView.image = [UIImage imageNamed:imageName];
//添加到要作用的laye上
[self.view.layer addAnimation:transition forKey:nil];
}
=====================
#pragma mark - 切换动画(转场动画)
- (void)changeCameraAnimation {
CATransition *changeAnimation = [CATransitionanimation];
changeAnimation.delegate =self;
changeAnimation.duration =0.45;
changeAnimation.type =@"oglFlip";
changeAnimation.subtype =kCATransitionFromRight;
changeAnimation.timingFunction =UIViewAnimationCurveEaseInOut;
[self.previewLayeraddAnimation:changeAnimationforKey:@"changeAnimation"];
}
6.UIView动画(
@interface UIView(UIViewAnimation)
)
[UIVIew animateWithDuration:<#(NSTimeInterval)#> animations:<#^(void)animations#>];
//添加到view上的动画
[UIView transitionWithView:self.view duration:1.0options:options animations:nil completion:nil];
头尾式动画:
改变frame的值(不可以直接修改frame的属性,要把frame保存到一个临时变量,修改临时变量的值,在吧临时变量的值赋回去)cgrect oldFrame = view.frame;
oldFrame.origin.x=10;
1.[UIView beginAnimations:nil context:nil];//开始动画
2.view.frame=oldFrame;
3.[UIVIew commitAnimations];//如果设置了动画时间,可以不提交动画.
/**
* UIViewAnimation
*
* @see http://www.cocoachina.com/bbs/read.php?tid=110168
*
* @brief UIView动画应该是最简单便捷创建动画的方式了,详解请猛戳URL.
*
* @method beginAnimations:context 第一个参数用来作为动画的标识,第二个参数给代理代理传递消息.至于为什么一个使用
* nil而另外一个使用NULL,是因为第一个参数是一个对象指针,而第二个参数是基本数据类型.
* @method setAnimationCurve: 设置动画的加速或减速的方式(速度)
* @method setAnimationDuration: 动画持续时间
* @method setAnimationTransition:forView:cache: 第一个参数定义动画类型,第二个参数是当前视图对象(设置动画方向),第三个参数是是否使用缓冲区
* @method commitAnimations 动画结束
*/
=========
//从一个oneview到twoview的过渡动画
[UIView transitionFromView:oneview toView:twoview UIViewAnimationOptionShowHideTransitionViews duration:1 options:UIViewAnimationOptionCurveEaseIn completion:nil];
//从一个view到另一个view过渡动画
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
UIViewAnimationOptionLayoutSubviews = 1 << 0,
UIViewAnimationOptionAllowUserInteraction = 1 << 1,// turn on user interaction while animating
UIViewAnimationOptionBeginFromCurrentState = 1 << 2,// start all views from current value, not initial value
UIViewAnimationOptionRepeat = 1 << 3,// repeat animation indefinitely
UIViewAnimationOptionAutoreverse = 1 << 4,// if repeat, run animation back and forth
UIViewAnimationOptionOverrideInheritedDuration = 1 << 5,// ignore nested duration
UIViewAnimationOptionOverrideInheritedCurve = 1 << 6,// ignore nested curve
UIViewAnimationOptionAllowAnimatedContent = 1 << 7,// animate contents (applies to transitions only)
UIViewAnimationOptionShowHideTransitionViews = 1 << 8,// flip to/from hidden state instead of adding/removing
UIViewAnimationOptionOverrideInheritedOptions = 1 << 9,// do not inherit any options or animation type
UIViewAnimationOptionCurveEaseInOut = 0 <<16,// default
UIViewAnimationOptionCurveEaseIn = 1 <<16,
UIViewAnimationOptionCurveEaseOut = 2 <<16,
UIViewAnimationOptionCurveLinear = 3 <<16,
UIViewAnimationOptionTransitionNone = 0 <<20,// default
UIViewAnimationOptionTransitionFlipFromLeft = 1 <<20,
UIViewAnimationOptionTransitionFlipFromRight = 2 <<20,
UIViewAnimationOptionTransitionCurlUp = 3 <<20,
UIViewAnimationOptionTransitionCurlDown = 4 <<20,
UIViewAnimationOptionTransitionCrossDissolve = 5 <<20,
UIViewAnimationOptionTransitionFlipFromTop = 6 <<20,
UIViewAnimationOptionTransitionFlipFromBottom = 7 <<20,
} NS_ENUM_AVAILABLE_IOS(4_0);
===================
+ (void)animationFlipFromLeft:(UIView *)view
{
[UIView beginAnimations:nilcontext:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];//设置动画的节奏
[UIView setAnimationDuration:0.35f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:viewcache:NO];//设置动画的方向
[UIViewcommitAnimations];
}
+ (void)animationFlipFromRigh:(UIView *)view
{
[UIView beginAnimations:nilcontext:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.35f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:viewcache:NO];
[UIViewcommitAnimations];
}
+ (void)animationCurlUp:(UIView *)view
{
[UIViewbeginAnimations:nilcontext:NULL];
[UIViewsetAnimationCurve:UIViewAnimationCurveEaseOut];
[UIViewsetAnimationDuration:0.35f];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:viewcache:NO];
[UIViewcommitAnimations];
}
+ (void)animationCurlDown:(UIView *)view
{
[UIViewbeginAnimations:nilcontext:NULL];
[UIViewsetAnimationCurve:UIViewAnimationCurveEaseIn];
[UIViewsetAnimationDuration:0.35f];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:viewcache:NO];
[UIViewcommitAnimations];
}
//动画的方向
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
transform:
redView.transform=CGAffineTransformMakeRotation(弧度)//修改旋转角度
redView.transform=CGAffineTransformMakeScale(1,1)//缩放
redView.transform=CGAffineTransformMaketranslation(1,1)//平移
在上一次的基础上旋转一定弧度:CGAffineTransformRotate(上一次的弧度,每次旋转的弧度);
7.UIView的block动画(
@interface UIView(UIViewAnimationWithBlocks)
)
//通过动画的方式 1s后让它消失
[UIView animateWithDuration:1.5 animations:^{
imageView.alpha = 0;
} completion:^(BOOL finished) {
[imageView removeFromSuperview];
}];
8.UIVIew之UIIMageView的帧动画(
@interface UIView (UIViewKeyframeAnimations)
)
UIImageView *imageV=[UIImageView alloc]initWithImage:[UIImage imageNamed:@""];
NSMutableArray *imageArr=[[NSMutableArrayalloc]init];
UIImage *image=[UIImageimageNamed:@""];
[imageArr addObject:image];
imageV.animationImages = imageArr;
//设置动画
imageV.animationDuration=2;//动画时长
imageV.animationRepeatCount=2;//重复播放次数
[imageV startAnimating];//开始动画
[imageV stopAnimating];//停止动画
[imageV isAnimating];//正在动画
****动画注意事项,按home键或页面消失再返回页面,动画会消失:https://blog.csdn.net/eric_xjj/article/details/8712427
解决:animation.removedOnCompletion = NO;
****简单的动画实例
//浇水,水壶旋转
-(void)waterFarm{
self.waterBottle.hidden=NO;
[UIView animateWithDuration:1 animations:^{
self.waterBottle.transform=CGAffineTransformMakeRotation(-0.4);
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 animations:^{
self.water.hidden=NO;
self.water.transform=CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
} completion:^(BOOL finished) {
self.water.transform=CGAffineTransformIdentity;
[UIView animateWithDuration:1 animations:^{
self.water.transform=CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
} completion:^(BOOL finished) {
self.water.transform=CGAffineTransformIdentity;
}];
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.9 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.waterBottle.hidden=YES;
self.water.hidden=YES;
self.waterBottle.transform=CGAffineTransformIdentity;
});
}];
}
//除草
-(void)weed{
UIColor *color = [UIColor redColor];
[color set]; //设置线条颜色
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 5.0;
aPath.lineCapStyle = kCGLineCapRound; //线条拐角
aPath.lineJoinStyle = kCGLineCapRound; //终点处理
float x=self.grass.x;
float y=self.grass.y;
[aPath moveToPoint:CGPointMake(x, y)];
[aPath addQuadCurveToPoint:CGPointMake(x+50, y-100) controlPoint:CGPointMake(x+10, y-80)];
CAKeyframeAnimation * keyframeAni = [CAKeyframeAnimation animation];
//设置属性
keyframeAni.keyPath = @"position";
keyframeAni.path = aPath.CGPath;
//速度控制函数,控制动画的节奏
keyframeAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
//设置动画时间
keyframeAni.duration = 1;
//3.把动画对象添加到要作用的layer上
[self.grass.layer addAnimation:keyframeAni forKey:nil];
//透明度动画
CABasicAnimation *showViewAnn = [CABasicAnimation animationWithKeyPath:@"opacity"];
showViewAnn.fromValue = [NSNumber numberWithFloat:1.0];
showViewAnn.toValue = [NSNumber numberWithFloat:0.0];
showViewAnn.duration = 1;
showViewAnn.fillMode = kCAFillModeForwards;
showViewAnn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
showViewAnn.removedOnCompletion = NO;
[self.grass.layer addAnimation:showViewAnn forKey:@"myShow"];
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 1;
group.removedOnCompletion = NO;
group.repeatCount = 1;
group.fillMode = kCAFillModeForwards;
[group setAnimations:@[keyframeAni,showViewAnn]];
[self.grass.layer addAnimation:group forKey:@"animationOpacity"];
}
//驱虫
-(void)killpest{
UIColor *color = [UIColor redColor];
[color set]; //设置线条颜色
UIBezierPath* aPath = [UIBezierPath bezierPath];
aPath.lineWidth = 5.0;
aPath.lineCapStyle = kCGLineCapRound; //线条拐角
aPath.lineJoinStyle = kCGLineCapRound; //终点处理
float x=self.pest.x;
float y=self.pest.y;
[aPath moveToPoint:CGPointMake(x, y)];
[aPath addQuadCurveToPoint:CGPointMake(x+50, y-100) controlPoint:CGPointMake(x, y-40)];
CAKeyframeAnimation * keyframeAni = [CAKeyframeAnimation animation];
//设置属性
keyframeAni.keyPath = @"position";
keyframeAni.path = aPath.CGPath;
//速度控制函数,控制动画的节奏
keyframeAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
//设置动画时间
keyframeAni.duration = 1;
//3.把动画对象添加到要作用的layer上
[self.pest.layer addAnimation:keyframeAni forKey:nil];
//透明度动画
CABasicAnimation *showViewAnn = [CABasicAnimation animationWithKeyPath:@"opacity"];
showViewAnn.fromValue = [NSNumber numberWithFloat:1.0];
showViewAnn.toValue = [NSNumber numberWithFloat:0.0];
showViewAnn.duration = 1;
showViewAnn.fillMode = kCAFillModeForwards;
showViewAnn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
showViewAnn.removedOnCompletion = NO;
[self.pest.layer addAnimation:showViewAnn forKey:@"myShow"];
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 1;
group.removedOnCompletion = NO;
group.repeatCount = 1;
group.fillMode = kCAFillModeForwards;
[group setAnimations:@[keyframeAni,showViewAnn]];
[self.pest.layer addAnimation:group forKey:@"animationOpacity"];
}
//施肥
-(void)shifeiliao{
self.shifeibag.hidden=NO;
[UIView animateWithDuration:1 animations:^{
self.shifeibag.transform=CGAffineTransformMakeRotation(-0.4);
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 animations:^{
self.shifei.hidden=NO;
self.shifei.transform=CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
} completion:^(BOOL finished) {
self.shifei.transform=CGAffineTransformIdentity;
[UIView animateWithDuration:1 animations:^{
self.shifei.transform=CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
} completion:^(BOOL finished) {
self.shifei.transform=CGAffineTransformIdentity;
}];
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.9 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.shifeibag.hidden=YES;
self.shifei.hidden=YES;
self.shifeibag.transform=CGAffineTransformIdentity;
});
}];
}
小树手势
//-(void)tapAnimateView:(UITapGestureRecognizer *)tap{
// NSLog(@"tap");
// [self UIViewAnimate];
//
//
//
//}
//UIVIew 动画
//-(void)UIViewAnimate{
CGFloat movedy=20;
// 只有树上下动,平移
// // [UIView animateWithDuration:0.5 animations:^{
// // self.treeView.height=self.treeView.height+movedy;
// // self.treeView.transform=CGAffineTransformMakeTranslation(0, -movedy);
// // } completion:^(BOOL finished) {
// // [UIView animateWithDuration:0.2 animations:^{
// // self.treeView.height=self.treeView.height-movedy;
// // self.treeView.transform=CGAffineTransformMakeTranslation(0, 0);
// // } completion:^(BOOL finished) {
// //
// // }];
// // }];
// //
// 缩放001
// // CGFloat scale=1.3;
// // CGFloat fh= self.treeView.height*(scale-1);//缩放前后的高度差
// // CGAffineTransform ctr1=CGAffineTransformMakeScale(1, 1);
// // CGAffineTransform ctr2= CGAffineTransformScale(ctr1, 1, scale);
// //CGAffineTransform ctr0=CGAffineTransformTranslate(ctr2, 0, -0.4*fh);//在ctr2缩放的基础上,水平方向不便宜,垂直方向偏移缩放前后高度差的一半
// // [UIView animateWithDuration:1 animations:^{
// // self.treeView.transform=ctr0;
// // } completion:^(BOOL finished) {
// // [UIView animateWithDuration:0.5 animations:^{
// // self.treeView.transform=CGAffineTransformIdentity;//还原
// // } completion:^(BOOL finished) {
// //
// // }];
// // }];
//
//
// //带缩放平移同步(实现图片底部的位置不变,往上平移并缩放)
// CGFloat scale=1.3;
// CGFloat fh= self.treeView.height*(scale-1);//缩放前后的高度差
// CGAffineTransform ctr1=CGAffineTransformMakeScale(1, scale);
// CGAffineTransform ctr0=CGAffineTransformMakeTranslation(0, -0.5*fh);
// [UIView animateWithDuration:1 animations:^{
// self.treeView.transform=CGAffineTransformConcat(ctr1, ctr0);
// } completion:^(BOOL finished) {
// [UIView animateWithDuration:0.5 animations:^{
// self.treeView.transform=CGAffineTransformIdentity;//还原
// } completion:^(BOOL finished) {
//
// }];
// }];
//}
小气泡缩放
//- (void)animationScaleOnceWithView:(UIView *)view
//{
// [UIView animateWithDuration:0.2 animations:^{
// view.transform = CGAffineTransformMakeScale(1.05, 1.05);
// } completion:^(BOOL finished) {
// [UIView animateWithDuration:0.2 animations:^{
// view.transform = CGAffineTransformMakeScale(1.0, 1.0);
// } completion:^(BOOL finished) {
// }];
// }];
//}
//
气泡上下移动
//- (void)animationUpDownWithView:(UIView *)view
//{
// CALayer *viewLayer = view.layer;
// CGPoint position = viewLayer.position;
// CGPoint fromPoint = CGPointMake(position.x, position.y);
// CGPoint toPoint = CGPointZero;
//
// uint32_t typeInt = arc4random() % 100;
// CGFloat distanceFloat = 0.0;
// while (distanceFloat == 0) {
// distanceFloat = (6 + (int)(arc4random() % (9 - 7 + 1))) * 100.0 / 101.0;
// }
// if (typeInt % 2 == 0) {
// toPoint = CGPointMake(position.x, position.y - distanceFloat);
// } else {
// toPoint = CGPointMake(position.x, position.y + distanceFloat);
// }
//
// CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
// animation.removedOnCompletion = NO;
// animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// animation.fromValue = [NSValue valueWithCGPoint:fromPoint];
// animation.toValue = [NSValue valueWithCGPoint:toPoint];
// animation.autoreverses = YES;
// CGFloat durationFloat = 0.0;
// while (durationFloat == 0.0) {
// durationFloat = 0.9 + (int)(arc4random() % (100 - 70 + 1)) / 31.0;
// }
// [animation setDuration:durationFloat];
// [animation setRepeatCount:MAXFLOAT];//无限重复
//
// [viewLayer addAnimation:animation forKey:nil];
//}
******动画卡顿的解决:
//因为setContentOffset animation有时候卡顿所以换成
-(void)setBgContentOffsetAnimation:(CGFloat )OffsetY
{ [UIView animateWithDuration:.25 animations:^
{
bgScrollView.contentOffset = CGPointMake(0, OffsetY);
}];
}
出现这种情况的原因有:
1:runloop 中原因
系统为了资源禁用了动画 和其他事件的接收
2:短时间多次调用此方法 系统取消了动画
3:跟其他动画冲突
任何在mainroop中的操作,花费的时间超过16ms的会导致应用程序放慢动画帧。