CALayer的寄宿图
CALayer 有一个属性叫做contents,它可以直接在图层中放置一张图片
@property contents
尽管类型被定义为id,赋值CGImage,真正要赋值的类型应该是CGImageRef,它是一个指向CGImage结构的指针。
事实上,contents这个奇怪的表现是由Mac OS的历史原因造成的。它之所以被定义为id类型,是因为在Mac OS系统上,这个属性对CGImage和NSImage类型的值都起作用。
ARC下,要给图层的寄宿图赋值,可以按照以下这个方法:
layer.contents = (__bridge id)image.CGImage;
在我们为视图赋值图片的时候,有时会遇到图片为了适应视图而进行拉伸等改变。解决方法就是把contentMode属性设置成更合适的值,像这样:
view.contentMode = UIViewContentModeScaleAspectFit;
CALayer与contentMode对应的属性叫做contentsGravity
@property contentsGravity
决定内容在图层的边界对齐方式, NSString 类型,默认值为kCAGravityResize,。
kCAGravityCenter,水平和垂直居中
kCAGravityTop,水平居中,垂直置顶边缘
kCAGravityBottom,水平居中,垂直置底边缘
kCAGravityLeft,水平居左边缘,垂直居中
kCAGravityRight,水平居右边缘,垂直居中
kCAGravityTopLeft,水平居左边缘,垂直置顶边缘
kCAGravityTopRight,水平居右边缘,垂直置顶边缘
kCAGravityBottomLeft,水平居左边缘,垂直置底边缘
kCAGravityBottomRight,水平居右边缘,垂直置底边缘
kCAGravityResize,调整大小以适应整个边界矩形
kCAGravityResizeAspect,整大小以适应边界矩形,保持内容方面。如果内容不完全填充边 界矩形,则内容集中在部分轴上.
kCAGravityResizeAspectFill。调整到完全填充边界矩形,同时仍然保留内容方面。内容集中在它超过的轴.
@property contentsScale
定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为1.0的浮点数
contentsScale属性其实属于支持高分辨率(又称Hi-DPI或Retina)屏幕机制的一部分。它用来判断在绘制图层的时候应该为寄宿图创建的空间大小,和需要显示的图片的拉伸度(假设并没有设置contentsGravity属性)。
这并不会对我们在使用kCAGravityResizeAspect时产生任何影响,因为它就是拉伸图片以适应图层而已,根本不会考虑到分辨率问题。但是如果我们把contentsGravity设置为kCAGravityCenter(这个值并不会拉伸图片),那将会有很明显的变化.
当用代码的方式来处理寄宿图的时候,一定要记住要手动的设置图层的contentsScale属性.
layer.contentsScale = [UIScreen mainScreen].scale;
@property maskToBounds
默认情况下,UIView仍然会绘制超过边界的内容或是子视图,在CALayer下也是这样的。UIView有一个叫做clipsToBounds的属性可以用来决定是否显示超出边界的内容,CALayer对应的属性叫做masksToBounds.
UIImage *image = [UIImage imageNamed:@"素材"];
//add it directly to our view's layer
self.layerView.layer.contents = (__bridge id)image.CGImage;
//正确地设置contentsGravity的值
self.layerView.layer.contentsGravity = kCAGravityCenter;
//set the contentsScale to match image
self.layerView.layer.contentsScale = [UIScreen mainScreen].scale;;
// 使用masksToBounds来修建图层内容
self.layerView.layer.masksToBounds = YES;
@property contentsRect
CALayer的contentsRect属性允许我们在图层边框里显示寄宿图的一个子域,contentsRect不是按点来计算的,它使用了单位坐标,单位坐标指定在0到1之间,是一个相对值(像素和点就是绝对值)。所以他们是相对与寄宿图的尺寸的,默认的contentsRect是{0, 0, 1, 1}.
iOS使用了以下的坐标系统:
点 —— 在iOS和Mac OS中最常见的坐标体系。点就像是虚拟的像素,也被称作逻辑像素。在标准设备上,一个点就是一个像素,但是在Retina设备上,一个点等于2*2个像素。iOS用点作为屏幕的坐标测算体系就是为了在Retina设备和普通设备上能有一致的视觉效果。
像素 —— 物理像素坐标并不会用来屏幕布局,但是仍然与图片有相对关系。UIImage是一个屏幕分辨率解决方案,所以指定点来度量大小。但是一些底层的图片表示如CGImage就会使用像素,所以你要清楚在Retina设备和普通设备上,他们表现出来了不同的大小。
单位 —— 对于与图片大小或是图层边界相关的显示,单位坐标是一个方便的度量方式, 当大小改变的时候,也不需要再次调整。单位坐标在OpenGL这种纹理坐标系统中用得很多,Core Animation中也用到了单位坐标。
contentsRect在app中最有趣的地方在于一个叫做image sprites(图片拼合)的用法。这个技术常用来指代载入拼合的图片,跟移动图片一点关系也没有。不过呢,你要是有兴趣在一些常见的app中使用拼合技术,那么一个叫做LayerSprites的开源库(https://github.com/nicklockwood/LayerSprites),它能够读取Cocos2D格式中的拼合图并在普通的Core Animation层中显示出来。
#pragma mark - 3.图片拼合
- (void)addSpriteImage:(UIImage *)image withContentRect:(CGRect)rect toLayer:(CALayer *)layer{
//set image
layer.contents = (__bridge id)image.CGImage;
//scale contents to fit
layer.contentsGravity = kCAGravityResizeAspect;
//set contentsRect
layer.contentsRect = rect;
}
- (void)imageSprites{
UIImage *image = [UIImage imageNamed:@"2.7"];
//set igloo sprite
[self addSpriteImage:image withContentRect:CGRectMake(0, 0, 0.5, 0.5) toLayer:self.igloo.layer];
//set cone sprite
[self addSpriteImage:image withContentRect:CGRectMake(0.5, 0, 0.5, 0.5) toLayer:self.cone.layer];
//set anchor sprite
[self addSpriteImage:image withContentRect:CGRectMake(0, 0.5, 0.5, 0.5) toLayer:self.anchor.layer];
//set spaceship sprite
[self addSpriteImage:image withContentRect:CGRectMake(0.5, 0.5, 0.5, 0.5) toLayer:self.layerView.layer];
}
@property contentsCenter
contentsCenter其实是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域。
默认情况下,contentsCenter是{0, 0, 1, 1},如果大小(由conttensGravity决定)改变了,那么寄宿图将会均匀地拉伸开。
如果我们增加原点的值并减小尺寸。我们会在图片的周围创造一个边框。
可以随意重设尺寸,边框仍然会是连续的。他工作起来的效果和UIImage里的-resizableImageWithCapInsets: 方法效果非常类似,只是它可以运用到任何寄宿图,甚至包括在Core Graphics运行时绘制的图形.contentsCenter可以在Interface Builder里面配置.
#pragma mark - 设置可拉伸视图
- (void)addStretchableImage:(UIImage *)image withContentCenter:(CGRect)rect toLayer:(CALayer *)layer
{
//set image
layer.contents = (__bridge id)image.CGImage;
//set contentsCenter
layer.contentsCenter = rect;
}
- (void)setStretchableImage{
UIImage *image = [UIImage imageNamed:@"素材"];
//set button 1
[self addStretchableImage:image withContentCenter:CGRectMake(0.25, 0.25, 0.5, 0.5) toLayer:self.layerView.layer];
//set button 2
[self addStretchableImage:image withContentCenter:CGRectMake(0.25, 0.25, 0.5, 0.5) toLayer:self.igloo.layer];
}