视觉效果

圆角

CALayer有一个叫做cornerRadius的属性控制着图层角的曲率。是一个浮点数,默认为0(为0的时候是直角)。默认情况下,这个曲率值只影响背景颜色而不影响背景图片或是子图层,不过如果把masksToBounds设置成YES的话,图层里面的所有的东西都会被截取。

图层边框

CALayer另外两个非常有用的属性就是borderWidthborderColor。这俩共同定义了图层边缘的绘制样式。
borderWidth是以点为单位的定义边框粗细的浮点数,默认是0。borderColor定义了边框的颜色,默认为黑色。它是CGColorRef类型,而不是UIColor。
边框是绘制在图层边界里面的,而且在所有子内容之前,也在子图层之前。边框是跟随图层的边界变化的,而不是图层里面的内容。

阴影

shadowOpacity给它设置一个(0.0,1.0]之间的浮点数就会显示阴影了。如果设置为1.0,将会显示一个有轻微模糊的黑色阴影稍微在图层之上。若要改动阴影的表现,那就要使用shadowColorshadowOffsetshadowRadius这三个属性了。

shadowOffset属性控制阴影的方向和距离。它是一个CGSize的值,宽度控制着阴影横向的位移,高度控制着纵向的位移。它的默认值是{0,-3},即阴影相对于Y轴有3个点的向上位移。

shadowRadius 属性控制着阴影的模糊度,当它的值为0的时候,阴影就和视图一样有一个非常确定的边界线。当值越来越大的时候,边界线看上去就会越来越模糊和自然。通常来讲,如果你想让视图或控件非常醒目独立于背景之外(比如弹出框遮罩层),你就应该给它设置一个稍大的值。阴影越模糊,图层的深度看上去就会越明显。

图层蒙版

通过masksToBounds属性,我们可以沿边界裁剪图形;通过cornerRadius我们可以设定一个圆角。但是有时候你希望展现的内容不是一个矩形或圆角矩形。比如,你想展示一个有星形框架的图片,又或者想让一些古卷文字慢慢渐变成背景色,而不是一个突兀的边界。
CALayer有一个属性叫做mask可以解决这个问题。这个属性本身就是个CALayer类型,有和其他图层一样的绘制和布局属性。它类似于一个子图层,相对于父图层布局,但它却不是一个普通的子图层,不同于那些绘制在父图层中的子图层,mask图层定义了父图层的部分可见区域。
mask图层的Color属性是无关紧要的,真正重要的是图层的轮廓。mask属性就像一个饼干切割机,mask图层实心部分会被保留下来,其他的则会被抛弃。
如果mask图层比父图层要小,只有在mask图层里面的内容才是它关心的,除此以外的一切都会被隐藏起来。

视觉效果_第1张图片

拉伸过滤

最后我们来拉拉minificationFiltermagnificationFilter属性。总得来讲,当我们视图显示一个图片的时候,都应该正确地显示这个图片(即1:1),原因如下:

  • 能够显示最好的画质,像素既没有被压缩也没有被拉伸。
  • 能更好的使用内存,因为这就是所有你要存储的东西。
  • 最好的性能表现,CPU不需要为此额外的计算。
    不过有时候,显示一个非真实大小的图片确实是我们需要的效果。比如说一个头像或是图片的缩略图,再比如说一个可以被拖拽和伸缩的大图。这些情况下,为同一图片的不同大小存储不同的图片显得又不切实际。
    当图片需要显示不同的大小的时候,有一种叫做拉伸过滤的算法就起到了作用了。它作用于原图的像素上并根据需要生成新的像素显示在屏幕上。
    事实上,重绘图片大小也没有一个统一的通用算法。这取决于需要拉伸的内容,放大或是缩小的需求等这些因素。CALayer为此提供了三种拉伸过滤方法:
  • kCAFilterLinear
  • kCAFilterNearest
  • kCAFilterTrilinear

minification(缩小图片)和magnification(放大图片)默认的过滤器都是kCAFilterLinear,这个过滤器采用双线性过滤波算法,它在大多数情况下都表现良好。双线性滤波算法通过对多个像素取样最终生成新的值,得到一个平滑的表现不错的拉伸。但是放大倍数比较大的时候图片就模糊不清了。
kCAFilterTrilinearkCAFilterLinear非常相似,大部分情况下二者都看不出来有什么差别。但是,较双线性滤波算法而言,三线性滤波算法存储了多个大小情况下的图片,并三维取样,同时结合大图和小图的存储进而得到最后的结果。
这个方法的好处在于算法能够从一系列已经接近与最终大小的图片中得到想要的结果,也就是说不要对很多像素同步取样。这不仅提高了性能,也避免了小概率因舍入错误引起的取样失灵的问题:

视觉效果_第2张图片

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

视觉效果_第3张图片

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

组透明

UIView有一个叫做alpha的属性来确定视图的透明度。CALayer有一个等同的属性叫做opacity,这两个属性都是影响子层级的。也就是说,如果你给一个图层设置了opacity属性,那它的子图层都会受此影响。

常见的做法是把一个控件alpha值设置为0.5,以使其看上去呈现为不可用状态。对于独立的视图来说还不错,但是当一个控件有子视图的时候就有点奇怪了,如下图所示:

视觉效果_第4张图片

这是由透明度的混合叠加造成的,当你显示一个50%透明度的图层时,图层的每个像素都会一半显示自己的颜色,另一半显示图层下面的颜色。这是正常的透明度的表现。但是如果图层包含一个同样显示50%透明的子图层时,你所看到的视图,50%来自子视图,25%来自子图层本身的颜色,另外的25%则来自背景色。

理想状况下,当你设置了一个图层的透明度,你希望它包含的整个图层树像一个整体一样的透明效果。你可以通过设置Info.plist文件中的UIViewGroupOpacity为YES来达到这个效果,但是这个设置会影响到这个应用,整个app可能会受到不良影响。
另一个方法就是,你可以设置CALayer的一个叫做shouldRasterize属性来实现组透明的效果,如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,这样就没有透明度混合的问题了。

@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIView *containerView;
@end

@implementation ViewController

- (UIButton *)customButton
{
  //create button
  CGRect frame = CGRectMake(0, 0, 150, 50);
  UIButton *button = [[UIButton alloc] initWithFrame:frame];
  button.backgroundColor = [UIColor whiteColor];
  button.layer.cornerRadius = 10;

  //add label
  frame = CGRectMake(20, 10, 110, 30);
  UILabel *label = [[UILabel alloc] initWithFrame:frame];
  label.text = @"Hello World";
  label.textAlignment = NSTextAlignmentCenter;
  [button addSubview:label];
  return button;
}

- (void)viewDidLoad
{
  [super viewDidLoad];

  //create opaque button
  UIButton *button1 = [self customButton];
  button1.center = CGPointMake(50, 150);
  [self.containerView addSubview:button1];

  //create translucent button
  UIButton *button2 = [self customButton];
  
  button2.center = CGPointMake(250, 150);
  button2.alpha = 0.5;
  [self.containerView addSubview:button2];

  //enable rasterization for the translucent button
  button2.layer.shouldRasterize = YES;
  button2.layer.rasterizationScale = [UIScreen mainScreen].scale;
}
@end
视觉效果_第5张图片

你可能感兴趣的:(视觉效果)