iOS CoreAnimation(2)-寄宿图

一、contents属性

CALayer有一个属性叫做contents,这个属性的类型被定义为id,意思是可以是任何类型的对象。但是如果contents赋的不是CGImage,那么图层将是空白的。

事实上,你真正要赋值的类型应该是CGImageRef,它是一个只想CGImage的结构的指针。UIImage有一个CGImage属性,它返回一个“CGImageRef“,如果把这个值赋值给CALayer的contents,将会出现编译错误,因为CGImageRef并不是一个真正的Cocoa对象,而是一个Core Foundation类型。

尽管Core Foundation类型跟Cocoa对象在运行时很像(被称作toll-free-bridging),他们并不是类型兼容的,不过你可以通过bridged关键字转换。

layer.contents = (__bridge id)image.CGImage;

这样我们就可以利用CALayer在一个普通的UIView中显示了一张图片,这不是一个UIImageView,它不是我们通常用来展示图片的方法。

1、contentGravity

类似UIView的属性contentMode,CALayer与contentMode对应的属性叫做contentGravity,但是它是一个NSString类型,而不是像对应的UIKit部分,那里面的值是枚举。contentGravity可选的常量值有以下一些:

  • kCAGravityCenter
  • kCAGravityTop
  • kCAGravityBottom
  • kCAGravityLeft
  • kCAGravityRight
  • kCAGravityTopLeft
  • kCAGravityTopRight
  • kCAGravityBottomLeft
  • kCAGravityBottomRight
  • kCAGravityResize
  • kCAGravityResizeAspect
  • kCAGravityResizeAspectFill

和contentMode一样,contentsGravity的目的是为了决定内容在图层的边界中怎么对齐。

由于图层坐标系x轴从左向右为正方向,y轴从上向下为正方向,所以Top在屏幕显示的下方。
2、contentsScale

contentsScale属性定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为1.0的浮点数。

如果contentsScale设置为1.0,将会以每个点1个像素绘制图片,如果设置为2.0,则会以每个点2个像素绘制图片,这就是Retina屏幕。

UIView有一个类似的功能但是非常少用到的contentScaleFactor属性。

当用代码的方式处理寄宿图的时候,一定记住要手动的设置图层的contentsScale属性,否则,你的图片在Retina设备上就显示的不正确啦。代码如下:

layer.contentsScale = [UIScreen mainScreen].scale;
3、maskToBounds

默认情况下,UIView仍然会绘制超过边界的内容或者子视图,在CALayer下也是这样。

UIView有一个clipToBounds属性可以用来决定是否显示超出边界的内容,同样CALayer对应的属性叫做maskToBounds,把它设置为YES,也可以达到同样效果。

4、contentsRect

CALayer的contentsRect属性允许我们在图层边框里显示寄宿图的一个子域。

和Bounds和Frame不同,contentsRect不是按点来计算的,它使用了单位坐标,单位坐标指定在0到1之间,是一个相对值。

默认的contentsRect是{0, 0, 1, 1},这以为这真个寄宿图默认都是可见的,如果制定一个小一点的矩形,图片就会被裁剪。

5、contentsCenter(九宫格)

contentsCenter其实是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域。改变contentsCenter的值并不会影响到寄宿图的显示,除非图层的大小改变了,才看到效果。

这其实是游戏开发中经常谈到的九宫格视图,它其实也使用了单位坐标

在Interface Builder里的Stretching表示contentsCenter属性,这样就不需要写代码控制了。

二、Custom Drawing

给Contents赋CGImage的值不是唯一的设置寄宿图的方法,我们也可以直接用Core Graphics直接绘制寄宿图。能够通过继承UIView并实现-drawRect: 方法来自定义绘制。

-drawRect: 方法没有默认的实现,因为对UIView来说,寄宿图并不是必须的,它不在意那到底是单调的颜色还是有一个图片的实例。如果UIView检测到-drawRect:方法被调用了,它就会为视图分配一个寄宿图,这个寄宿图的像素尺寸等于视图大小乘以contentsScale的值。

如果你不需要寄宿图,那就不要创建这个方法了,这会造成CPU资源和内存的浪费,这就是为什么苹果建议:如果没有自定义绘制的任务就不要在子类中写一个空-drawRect:方法。

CALayer有一个可选的delegate属性,实现了CALayerDelegate协议,当CALayer需要一个内容特定的信息时,就会从协议中请求。CALayerDelegate是一个非正式协议,其实就是说没有CALayerDelegate @protocol可以让你在类里面引用啦。

当需要重绘时,CALayer会请求它的代理给他一个寄宿图来显示,通过调用以下方法:

- (void)displayLayer:(CALayer *)layer;

这里代理就可以直接设置contents属性了。如果代理不实现displayLayer方法,CALayer就会转而尝试调用下面这个方法:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;

在调用这个方法之前,CALayer创建了一个合适尺寸的空寄宿图和一个Core Graphics的绘制上下文环境,为绘制寄宿图做准备,他作为ctx参数传入。

  • 在layer上显式调用了-display。不同于UIView,当图层显示在屏幕上时,CALayer不会自动重绘它的内容。它把重绘的决定权交给了开发者。
  • 尽管我们没使用masksToBounds属性,绘制的那个圆仍然沿边界被裁剪了。这是因为当你使用CALayerDelegate绘制寄宿图的时候,并没有对超出边界外的内容提供绘制。

当创建UIView时,UIView创建了它的寄宿图是,它会自动把图层的delegate设置为自己,UIView为我们做了以下所有的事情。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值