iOS Core Animation--视觉效果

CALayer属性实现的视觉效果–圆角、图层边框、阴影、图层蒙版、拉伸过滤、以及组透明。下面将一一介绍

一、圆角
cornerRadius:使用CALayer的cornerRadius属性设置图层的曲率,可以实现圆角;它的默认值是0为直角。

       谨记:默认情况下cornerRadius只影响背景颜色而不影响背景图片或子图层。不过设置masksToBounds为yes,图层里面的所有东西都会被截取。

下面的例子中设置了两个view,每个view中又各自包含一个子视图,将两个view的cornerRadius设置为20,然后将第二个视图的masksToRadius设置为yes。

- (void)viewDidLoad {
    [super viewDidLoad];

    //布局,两个view,view1以及其子视图view11,view2以及其子视图view22
    UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(50, 100, kGetViewWidth(self.view)/2, 200)];
    view1.backgroundColor = [UIColor lightGrayColor];
    UIView *view11 = [[UIView alloc]initWithFrame:CGRectMake(10, 0, kGetViewWidth(self.view)/3, 100)];
    view11.backgroundColor = [UIColor redColor];
    [self.view addSubview:view1];
    [view1 addSubview:view11];

    UIView *view2 = [[UIView alloc]initWithFrame:CGRectMake(50, 400, kGetViewWidth(self.view)/2, 200)];
    view2.backgroundColor = [UIColor lightGrayColor];;
    UIView *view22 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, kGetViewWidth(self.view)/3, 100)];
    view22.backgroundColor = [UIColor redColor];
    [self.view addSubview:view2];
    [view2 addSubview:view22];

    //设置view1,view2的Layer属性的cornerRadius
    view1.layer.cornerRadius = 20.0f;
    view2.layer.cornerRadius = 20.0f;

    //设置view1的图片后,view1的图片说明CornerRadius只影响背景颜色而不影响背景图片或子图层
    // UIImage *image = [UIImage imageNamed:@"jj.jpg"];
    //view1.layer.contents = (__bridge id)image.CGImage;

    //设置view2的maskToBounds
    view2.layer.masksToBounds = YES;

}

这里写图片描述

 从运行的结果可以看出,默认时cornerRadius只影响背景颜色不影响子视图或子图层。不过可以使用masksToBounds来弥补这一点。

二、图层边框
borderWidth和borderColor:CALayer使用borderWidth和borderColor共同绘制图层边框的样式,边框绘制在图层边界里面,随图层的边界变化,显示在所有子内容或子图层的前面。
—borderWidth以点为单位定义边框的粗细,默认为0
—borderColor设置边框的颜色,默认为黑色,类型是CGColorRef类型,通过assign声明。

    //使用图层的borderWidth是以点为单位设置边框,默认为0f
    view1.layer.borderWidth  = 5.0f;
    view2.layer.borderWidth  = 5.0f;

    //borderColor设置边框的颜色
    view2.layer.borderColor  = [UIColor yellowColor].CGColor;

运行结果:
这里写图片描述

三、阴影
1、阴影的简单使用
在页面使用阴影可以强调正在显示的图层和优先级,又或许阴影只是装饰,图层的阴影继承自内容的外形,Core Animation会将寄宿图包括子视图等都考虑在内来创建阴影

—shadowOpacity设置阴影的透明度
—shadowColor设置阴影的颜色
—shadowOffset设置阴影在横向和纵向的偏移量,默认为{0,-3}
—shadowRadius设置阴影的模糊度

    //shadowOpacity阴影的透明度,在0.0(完全透明)~1.0(不透明,黑色的向左上偏的阴影)
    view1.layer.shadowOpacity = 1;
    view1.layer.shadowColor   = [UIColor blackColor].CGColor;

    //shadowOffset设置阴影的方向的偏移以及纵向的偏移,默认{0,-3}阴影显示为在上方向左偏移,CGSizeMake(10, 10);向右向下偏移
    view1.layer.shadowOffset  = CGSizeMake(10, 10);

    //shadowRadius设置阴影的模糊度;值越大,模糊的区域越大
    view1.layer.shadowRadius  = 10;

运行结果:
这里写图片描述

2、阴影的裁剪
问题:如果图层的maskToBounds属性为yes是只显示图层中的内容,所有从图层中突出来的内容都会被裁剪,所以设置maskToBounds为yes后,阴影不会显示
解决:需要使用两个图层:一个只画阴影的外图层和一个是用maskToBounds沿边界裁剪的内图层(内图层放在外图层里面)

//shadowView为设置图层阴影的外图层
UIView *shadowView = [[UIView alloc]initWithFrame:CGRectMake(50, 100, kGetViewWidth(self.view)/2, 200)];
[self.view addSubview:shadowView];
shadowView.layer.shadowOpacity = 0.5f;
shadowView.layer.shadowOffset  = CGSizeMake(10, 10);
shadowView.layer.shadowRadius  = 10;



UIView *view1 = [[UIView alloc]initWithFrame:CGRectMake(50, 100, kGetViewWidth(self.view)/2, 200)];
view1.backgroundColor = [UIColor lightGrayColor];
[shadowView addSubview:view1];//注意内图层放在外图层的内部


//shadowOpacity阴影的透明度,在0.0(完全透明)~1.0(不透明,黑色的向左上偏的阴影)
view1.layer.shadowOpacity = 1;
view1.layer.shadowColor   = [UIColor blackColor].CGColor;
//shadowOffset设置阴影的方向的偏移以及纵向的偏移,默认{0,-3}阴影显示为在上方向左偏移,CGSizeMake(10, 10);向右向下偏移
view1.layer.shadowOffset  = CGSizeMake(10, 10);

//shadowRadius设置阴影的模糊度;值越大,模糊的区域越大
view1.layer.shadowRadius  = 10;

///view1.layer.masksToBounds = YES;引发问题;使用两个图层
view1.layer.masksToBounds = YES;

三、shadowPath

前面介绍过阴影是继承图层内容来绘制的;如果图层有很多子图层而且每个子图层还有一个透明的寄宿图的话,实时计算阴影非常耗资源

如果事先知道阴影的形状,我们自己绘制阴影形状就可以了,shadowPath属性可以帮助我们,shadowPath是一个CGPathRef类型,CGPathRef实际上是指向CGPath的指针。CGPath是Core Graphics对象,用来指定任意一个矢量图形
如果阴影的形状复杂,可以使用UIBezierPath类绘制

  //view2设置园形的阴影
    CGMutablePathRef circlePath = CGPathCreateMutable();
    CGPathAddEllipseInRect(circlePath, NULL, view2.bounds);
    view2.layer.shadowPath = circlePath;
    CGPathRelease(circlePath);

四、图层蒙版
CALayer的有一个mask属性,它是CALayer类型;所以它类似于子图层,有和其他图层一样的绘制和布局属性,但也有不同之处,mask图层定义了父图层的部分可见区域。mask图层的Color属性无关紧要,重要的图层的轮廓;mask只保留实心部分,其他的会被抛弃

图片和蒙版图层作用的效果

CALayer 蒙版图层真正厉害的地方在于蒙版图层不局限于静态图。任何有图层构成的都可以作为mask属性,这意味着你的蒙版可以通过代码甚至是动画实时生成!

核心代码

    //创建maskLayer
    CALayer *maskLayer = [CALayer layer];

    //给maskLayer 设定frame
    maskLayer.frame = self.layerView1.bounds;

    //"phone.png"为圆形图片
    UIImage *maskImage = [UIImage imageNamed:@"phone.png"];

    //给图层的contents添加内容
    maskLayer.contents = (__bridge id)maskImage.CGImage;

    self.layerView1.layer.mask = maskLayer;

结果:这里写图片描述

五、拉伸过滤

minificationFilter和magnificationFilter属性:
总得来讲,当我们视图显示一个图片的时候,都应该正确地显示这个图片(意即:以正确的比例和正确的1:1像素显示在屏幕上)。原因如下:

能够显示最好的画质,像素既没有被压缩也没有被拉伸。
能更好的使用内存,因为这就是所有你要存储的东西。
最好的性能表现,CPU不需要为此额外的计算。

不过有时候,显示一个非真实大小的图片确实是我们需要的效果。比如说一个头像或是图片的缩略图,再比如说一个可以被拖拽和伸缩的大图。这些情况下,为同一图片的不同大小存储不同的图片显得又不切实际。

当图片需要显示不同的大小的时候,有一种叫做拉伸过滤的算法就起到作用了。它作用于原图的像素上并根据需要生成新的像素显示在屏幕上。

事实上,重绘图片大小也没有一个统一的通用算法。这取决于需要拉伸的内容,放大或是缩小的需求等这些因素。CALayer为此提供了三种拉伸过滤方法,他们是:

kCAFilterLinear
kCAFilterNearest
kCAFilterTrilinear

minification(缩小图片)和magnification(放大图片)默认的过滤器都是kCAFilterLinear,这个过滤器采用双线性滤波算法,它在大多数情况下都表现良好。双线性滤波算法通过对多个像素取样最终生成新的值,得到一个平滑的表现不错的拉伸。但是当放大倍数比较大的时候图片就模糊不清了。

kCAFilterTrilinear和kCAFilterLinear非常相似,大部分情况下二者都看不出来有什么差别。但是,较双线性滤波算法而言,三线性滤波算法存储了多个大小情况下的图片(也叫多重贴图),并三维取样,同时结合大图和小图的存储进而得到最后的结果。

这个方法的好处在于算法能够从一系列已经接近于最终大小的图片中得到想要的结果,也就是说不要对很多像素同步取样。这不仅提高了性能,也避免了小概率因舍入错误引起的取样失灵的问题
这里写图片描述
图4.14 对于大图来说,双线性滤波和三线性滤波表现得更出色

kCAFilterNearest是一种比较武断的方法。从名字不难看出,这个算法(也叫最近过滤)就是取样最近的单像素点而不管其他的颜色。这样做非常快,也不会使图片模糊。但是,最明显的效果就是,会使得压缩图片更糟,图片放大之后也显得块状或是马赛克严重。
这里写图片描述
图4.15 对于没有斜线的小图来说,最近过滤算法要好很多

总的来说,对于比较小的图或者是差异特别明显,极少斜线的大图,最近过滤算法会保留这种差异明显的特质以呈现更好的结果。但是对于大多数的图尤其是有很多斜线或是曲线轮廓的图片来说,最近过滤算法会导致更差的结果。换句话说,线性过滤保留了形状,最近过滤则保留了像素的差异。

六、组透明

  UIView的alpha属性和CALayer的opacity属性都是用来设置透明度的,但是它们都影响子层级。

这里写图片描述

例如:自定义的Butt中内嵌Lable,然后设置button的alpha为0.5使其显示为不可用状态;但是里面的标签轮廓与按钮不搭。
这里写图片描述
这个实验我没有看到叠加效果,我只有iOS9系列的模拟器,不知道是不是这个原因

需求:设置图层opacity的透明度时,希望整个图层树显示整体的透明度
方法:(1)设置info.plist中UIViewGroupOpacity为 YES,但影响整个app
(2)设置CALayer的shouldRasterize属性为YES,实现组透明,在应用透明度之前,图层和子图层被整合成一张整体的图片了。为启用shouldRasterize,我们需要设置rasterizationScale属性匹配屏幕,防止Retina屏幕像素化

  button2.layer.shouldRasterize = YES;
  button2.layer.rasterizationScale = [UIScreen mainScreen].scale;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的修养

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值