ios动画

寄宿图

2017-08-04  本文已影响81人  无题007

看到这个名字可能会一脸懵逼,什么是寄宿图啊?简单的来说就是图层中包含的图。

contents属性

CALayer有一个属性叫做contents,这个属性的类型被定义为id,意味着它可以是任何类型的对象。在这种情况下,你可以给contents属性赋任何值。但在实践中,如果你给contents赋的不是CGImage,那么你得到的图层将是空白的。
contents这个奇怪的表现是由Mac OS 的历史原因造成的。它之所以被定义为id类型,是因为在Mac OS系统上,这个属性对CGImage和NSImage类型的值都起作用。如果你视图在iOS平台上将UIImage的值赋给它,只能得到一个空白的图层。
令人头疼的时还不是这个问题,事实上,你真正要赋值的类型应该是CGImageRef,它是一个指向CGImage结构的指针。UIImage有一个CGImage属性,它返回一个“CGImageRef”,如果你想把这个值直接赋值给CALayer的contents,那你将会得到一个编译错误。因为CGImageRef并不是一个真正的Cocoa对象,而是一个Core Foundation类型。
尽管Core Foundation 类型跟Cocoa对象在运行时貌似很像,他们并不是类型兼容的,不过你可以通过bridged关键字转换。如果要给图层的寄宿图赋值,你可以按照以下方法:

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

下面我们继续修改上一篇建的工程:我们这里直接把view的宿主图层的contents属性设置成图片:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.view.backgroundColor = [UIColor grayColor];
    UIView *view = [[UIView alloc]init];
    view.frame = CGRectMake(80,200, 200, 200);
    view.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:view];
    
    UIImage *image = [UIImage imageNamed:@"tupian"];
    view.layer.contents = (__bridge id)image.CGImage;
}

运行结果:


是不是有点意思了~

contentGravity

现在感觉这个图片有些不好看啊,有些拉伸了~ 在使用UIImageView的时候遇到过同样的问题,解决的办法就是把contentMode属性设置成更合适的值:

view.contentMode = UIViewContentModeScaleAspectFit;

这个方法基本和我们遇到的情况的解决方法已经接近了,不过UIView大多数视觉相关的属性比如contentMode,对这些属性的操作其实是对 对应图层的操作。
CALayer与contentMode对应的属性叫做contentsGravity但是它是一个NSString类型,而不是像对应的UIKit部分,那里面的值是枚举。contentsGravity可选的常量值有以下这些:

 view.layer.contentsGravity = kCAGravityResizeAspect;

contentsScale

contentsScale属性定义了寄宿图的像素尺寸和视图大小的比例,默认情况下它是一个值为1.0的浮点数。contentsScale的目的并不是那么明显。它并不是总会对屏幕上的寄宿图有影响。如果你尝试对我们的例子设置不同的值,你就会发现根本没任何影响。 因为contents由于设置了contentsGravity属性,所以它已经被拉伸以适应图层的边界。
如果你只是单纯的想放大图层的contents图片,你可以通过使用图层的transformaffineTransform属性来达到这个目的。
contentsScale属性其实属于支持高分辨率屏幕机制的一部分。它用来判断在绘制图层的时候应该为寄宿图创建的控件大小,和需要显示的图片的拉伸度。UIView有一个类似的功能但是非常少用到的contentScaleFactor属性。

如果contentsScale设置为1.0,将会以每个点1像素绘制图片,如果设置为2.0,则会以每个点2个像素绘制图片,这就是我们熟知的Retina屏幕。
这并不会对我们在使用kCAGravityResizeAspect时产生任何影响,因为它就是拉伸图片以适应图层而已,根本不会考虑到分辨率问题。但是如果我们把contensGravity设置为kCAGravityCenter,那么将会有很明显的变化:

 view.layer.contentsGravity = kCAGravityCenter;//kCAGravityResizeAspect;
view.layer.contentsScale = [UIScreen mainScreen].scale;
view.layer.contentsGravity = kCAGravityCenter;//kCAGravityResizeAspect;
view.layer.contentsScale = image.scale;

当用代码的方式来处理寄宿图的时候,一定要记住要手动的设置图层contentsScale属性。

maskToBounds

UIView有一个叫做clipsToBounds的属性可以决定是否显示超出边界的内容,CALayer对应的属性叫做maskToBounds,把它设置为YES。

contentsRect

CALayer的contentsRect属性允许我们在图层边框里显示寄宿图的一个子域。这涉及到图片是如何显示和拉伸的,所以比contentsGravity灵活多了。
boundsframe不同,contentsRect不是按点来计算的,它使用了单位坐标,单位坐标指定在0到1之间,是一个相对值。所以他们是相对与寄宿图的尺寸的。
默认的contentsRect是{0,0,1,1},这意味着整个寄宿图默认都是可见的,如果我们指定一个小一点的矩形,图片就会被裁剪:

 view.layer.contentsRect = CGRectMake(0, 0, 0.5, 0.5);

事实上给contentsRect设置一个负数的原点或是大于{1,1}的尺寸也是可以的。你可以试一下哦_(可以做拼合图:像平常一样载入我们的大图,然后把它赋值给N个独立的图层的contents,然后设置每个图层的contentsRect来去掉我们不想显示的部分)

contentsCenter

不要被它的名字欺骗了,这是一个CGRect,它定义了一个固定的边框和一个在图层上可拉伸的区域。改变contensCenter的值并不会影响到寄宿图的显示,除非这个图层的大小改变了,你才能看到效果。

默认情况下,contentsCenter是{0,0,1,1},这意味着如果大小(由contentsGravity决定)改变了,那么寄宿图将会均匀地拉伸开。但是如果我们增加原点的值并减小尺寸。我们会在图片的周围创造一个边框。下图是contentsCenter设置为{0.25,0.25,0.5,0.5}的效果:

这意味着我们可以随意重设尺寸,边框仍然会是连续的。他工作起来的效果和UIImage里的resizableImageWithCapInsets:方法效果非常类似,只是它可以运用任何寄宿图,甚至包括在Core Graphics运行时绘制的图形。

上一篇 下一篇

猜你喜欢

热点阅读