iOS 中有很多方法可以实现动画,我们可以用 CAKeyframeAnimation, CABasicAnimation,CASpringAnimation(iOS9.0 中添加的,实现弹簧的效果),也可以用 UIView 中为我们提供的动画接口,不管用哪种方法,目的就是实现动画效果,这里重点讲解 CAKeyframeAnimation 和 CABasicAnimation。
在学习动画之前,我们需要了解一些知识,大家都知道动画是作用在图层上面的,我们首先要了解图层。
大家平时使用最多的就是 UIView,我们创建一个视图时,其实就是创建了一个与视图相关的图层,视图负责管理着创建的图层,通过图层来显示相应内容。我们可以直接创建一个图层,然后将它添加到父图层上,这样就能看到我们创建的图层(代码如下)
- CALayer * layer = [CALayer layer];
- layer.frame = CGRectMake(50, 200, 80, 80);
- layer.backgroundColor = [UIColor greenColor].CGColor; [self.view.layer addSublayer: layer];
效果图:
可能大家想知道 CALayer 和 UIView 的区别在哪?也许最大的区别就是 UIView 可以和用户交互,CALayer 不能交互。相信我们的目的并不是显示一个纯色的矩形块,其实 CALayer 也可以显示其他类型的内容。
查看头文件可以知道这个属性的类型为 id,也就是说他可以显示任何类型的对象,但实践中,如果不是 CGImage 类型,将会显示空白,这点会让人产生疑惑,其实还有更奇怪的,你要赋给的类型不是 CGImage,而是 CGImageRef(指向 CGImage 结构的指针),UIImage 有一个 CGImage 属性,返回 CGImageRef,但是如果把这个值直接赋给 contents 的话会得到编译错误,因为 CGImageRef 是一个 Core Foundation 类型,我们需要用如下代码进行赋值:
- layer.contents = (__bridge id) image.CGImage;
以上代码块的前提是使用 ARC,不使用 ARC 的话,不需要__bridge
接下来我们来显示一张图片,代码如下:
- // 图片是一个200x200的图,layer的frame故意设置成矩形,为了演示变形
- UIImage * image = [UIImage imageNamed: @"image.png"];
- CALayer * layer = [CALayer layer];
- layer.frame = CGRectMake(50, 150, 80, 100);
- layer.contents = (__bridge id) image.CGImage; [self.view.layer addSublayer: layer];
效果图如下:
如上面代码所示,我们得到了一个变形了的图片,这当然不是我们想要的,如果想让图片正确显示,我们可以设置 contentGravity,这个属性用法类似 UIView 中的 contentMode 属性,我们可以看一下它的枚举:
是不是看着很熟悉啊!这对上面图片变形,我们可以设置这个属性值为 kCAGravityResizeAspect,这样就能得到我们想要的正确的效果了
添加代码:
- layer.contentsGravity = kCAGravityResizeAspect;
就能得到显示正确的图:
contentsScale 属性定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为 1.0 的浮点数。
如果你设置了 contentsGravity 属性,contentsScale 就不在寄宿图有影响,因为它已经被拉伸以适应图层的边界。
contentsScale 属性其实属于支持高分辨率(又称 Hi-DPI 或 Retina)屏幕机制的一部分,它用来判断在绘制图层的时候应该为寄宿图创建的空间大小,和需要显示的图片的拉伸度(假设并没有设置
属性),UIView 有一个类似功能但是非常少用到的
- contentsGravity
属性。
- contentScaleFactor
如果把 contentsGravity 设置成 kCAGravityCenter,我们看到图片超出了视图边界
UIView 有一个叫做
的属性可以用来决定是否显示超出边界的内容,CALayer 对应的属性叫做
- clipsToBounds
,把它设置为 YES,即可看到图片被剪切了,如下图:
- masksToBounds
给
赋 CGImage 的值不是唯一的设置寄宿图的方法。我们也可以直接用 Core Graphics 直接绘制寄宿图。能够通过继承 UIView 并实现
- contents
方法来自定义绘制。
- -drawRect:
如果你不需要寄宿图,那就不要创建这个方法了,这会造成 CPU 资源和内存的浪费,这也是为什么苹果建议:如果没有自定义绘制的任务就不要在子类中写一个空的 - drawRect: 方法。
当视图出现在屏幕上时,-drawRect: 方法会被调用,通常是开发者自己调用 - setNeedsDisplay 方法
CALayer 有一个可选的
属性,实现了
- delegate
协议,当 CALayer 需要一个内容特定的信息时,就会从协议中请求。
- CALayerDelegate
当需要被重绘时,CALayer 会请求它的代理给它一个寄宿图来显示。它通过调用下面这个方法做到的:
- - (void) displayLayer: (CALayer * ) layer
如果代理想直接设置
属性的话,它就可以在这个方法中做,不然没有别的方法可以调用了
- contents
如果代理不实现
方法,CALayer 就会转而尝试调用下面这个方法:
- -displayLayer:
- - (void) drawLayer: (CALayer * ) layer inContext: (CGContextRef) ctx
在调用这个方法之前,CALayer 创建了一个合适尺寸的空寄宿图(尺寸由
和
- bounds
决定)和一个 Core Graphics 的绘制上下文环境,为绘制寄宿图做准备,它作为 ctx 参数传入。
- contentsScale
如下例子:
代码:
- (void)viewDidLoad {
[super viewDidLoad];
CALayer *blueLayer = [CALayer layer];
blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
blueLayer.backgroundColor = [UIColor blueColor].CGColor;
blueLayer.delegate = self;
blueLayer.contentsScale = [UIScreen mainScreen].scale; //add layer to our view
[self.view.layer addSublayer:blueLayer];
[blueLayer display];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextSetLineWidth(ctx, 5);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextStrokeEllipseInRect(ctx, layer.bounds);
}
效果图:
来源: http://www.cnblogs.com/Devhwl/p/7110835.html