Core Animation (四) Visual Effects
07 Oct 2013Visual Effects (四)
圆角
IOS UI 的一个显著特点就是无处不在的圆角矩形,从主屏的图标,alert,文本输入框。我们也可以在程序中创建圆角矩形,而不需要Photoshop。
CAlayer 有个 cornerRadius 属性可以控制Layer 直角的弯曲度。它是一个默认值为零的浮点值。默认的情况下,圆角的效果只会影Layer的背景颜色,并不会影响你设置的背景图片,或者加在Layer上面的SubLayer,masksToBounds设置为 YES 可以实现裁切SubLayer的功能。代码如下
UIView *greenView = [[UIView alloc] initWithFrame:CGRectMake(100,100 , 160, 160)];
greenView.backgroundColor = [UIColor greenColor];
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(-20,-20, 60, 60)];
redView.backgroundColor = [UIColor redColor];
[greenView addSubview:redView];
greenView.layer.cornerRadius = 20;
[self.view addSubview:greenView];
当设置了
greenView.layer.masksToBounds = YES;
效果就是这样的,红色的layer的右上角也被剪切了。
Layer Borders
CALayer另外一个非常有用的属性就是 borderWidth 和 borderColor 这两个属性组合起来控制Layer的边框。 borderColor 的类型不是UIColor 是 CGColorRef。 边框是是绘制在Layer的bounds里面并且覆盖在其他所有的 SubLayer 的上面。我们还用这个greenView 来做实验。
greenView.layer.borderWidth = 5.0f;
Drop Shadows
对于IOS的设计来说,另外一个特征就是阴影。当我们给Layer 的 shadowOpacity 属性设置了一个大于零的值,阴影就会出现在 Layer 的后面。 shadowOpacity 是一个 大于0.0(透明) 小于1.0(全黑) 的浮点数。此外,我们还可以通过 shadowColor, shadowOffset, shadowRadius来调整 阴影的效果。
UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(100, 80, 150, 150)];
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(300, 80, 150, 150)];
viewA.backgroundColor = [UIColor greenColor];
viewB.backgroundColor = [UIColor redColor];
viewA.layer.shadowOpacity = 1.0;
viewB.layer.shadowOpacity = 0.5;
viewA.layer.shadowOffset = CGSizeMake(0, -15);
viewB.layer.shadowOffset = CGSizeMake(5, 5);
viewA.layer.shadowRadius = 30;
viewB.layer.shadowRadius = 1;
viewA.layer.shadowColor = [UIColor redColor].CGColor;
viewB.layer.shadowColor = [UIColor greenColor].CGColor;
[self.view addSubview:viewA];
[self.view addSubview:viewB];
Shadow Clipping
和Layer的边框不一样,阴影会依照Layer包含的内容的确切的形状来显示。还有一个问题就是当使用 masksToBounds 的时候,阴影的显示也会有问题。
UIView *redViewA = [[UIView alloc] initWithFrame:CGRectMake(-20,-20, 70, 70)];
redViewA.backgroundColor = [UIColor redColor];
UIView *redViewB = [[UIView alloc] initWithFrame:CGRectMake(-20,-20, 70, 70)];
redViewB.backgroundColor = [UIColor redColor];
UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(100, 80, 150, 150)];
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(300, 80, 150, 150)];
viewB.layer.masksToBounds = YES;
[viewA addSubview:redViewA];
[viewB addSubview:redViewB];
viewB.backgroundColor = [UIColor greenColor];
viewA.backgroundColor = [UIColor greenColor];
viewA.layer.shadowOffset = CGSizeMake(0, 10);
viewB.layer.shadowOffset = CGSizeMake(0, 10);
viewA.layer.shadowOpacity = 0.7;
viewB.layer.shadowOpacity = 0.7;
viewB因为使用了 layer.masksToBounds = YES; 导致阴影消失了。我们怎么解决这个问题呢? 给viewB一个同样大小的superView 叫这个superView 添加阴影。下面的代码是这个问题的解决方法。
UIView *redViewA = [[UIView alloc] initWithFrame:CGRectMake(-20,-20, 70, 70)];
UIView *redViewB = [[UIView alloc] initWithFrame:CGRectMake(-20,-20, 70, 70)];
redViewA.backgroundColor = [UIColor redColor];
redViewB.backgroundColor = [UIColor redColor];
UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(100, 80, 150, 150)];
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150, 150)];
viewB.layer.masksToBounds = YES;
[viewA addSubview:redViewA];
[viewB addSubview:redViewB];
viewB.backgroundColor = [UIColor greenColor];
viewA.backgroundColor = [UIColor greenColor];
viewA.layer.shadowOffset = CGSizeMake(0, 10);
viewB.layer.shadowOffset = CGSizeMake(0, 10);
viewA.layer.shadowOpacity = 0.7;
viewB.layer.shadowOpacity = 0.7;
UIView *shadowViewB = [[UIView alloc] initWithFrame:CGRectMake(300, 80, 150, 150)];
shadowViewB.layer.shadowOffset = CGSizeMake(0, 10);
shadowViewB.layer.shadowOpacity = 0.7f;
[shadowViewB addSubview:viewB];
[self.view addSubview:viewA];
[self.view addSubview:shadowViewB];
这样一来 ViewB也有阴影啦。
ShadowPath
有时候我们给 Layer 添加的阴影并不总是正方形,如果我们想要其他形状的阴影怎么办呢。这时候 shadowPath 就派上用场了。阴影的实时计算是非常消耗手机性能的,尤其是当 Layer 包含大量的 带 alpha 遮罩 sublayer 的时候。 ShadowPath 是一个 CGPathRef (CGPath 的指针)。CGPath 是一个Core Graphics 的用来表示矢量形状的对象。我们可以用它来定义shadow的形状。
UIView *viewA = [[UIView alloc] initWithFrame:CGRectMake(100, 80, 100, 100)];
UIView *viewB = [[UIView alloc] initWithFrame:CGRectMake(300, 80, 100, 100)];
viewB.backgroundColor = [UIColor greenColor];
viewA.backgroundColor = [UIColor greenColor];
viewA.layer.shadowOpacity = 0.5;
viewB.layer.shadowOpacity = 0.5;
CGMutablePathRef squarePath = CGPathCreateMutable();
CGPathAddRect(squarePath, NULL, CGRectMake(-25, -25, 150, 150));
viewA.layer.shadowPath = squarePath;
CGPathRelease(squarePath);
CGMutablePathRef circlePath = CGPathCreateMutable();
CGPathAddEllipseInRect(circlePath, NULL,CGRectMake(-25, -25, 150, 150));
viewB.layer.shadowPath = circlePath;
CGPathRelease(circlePath);
[self.view addSubview:viewA];
[self.view addSubview:viewB];
当我们绘制一些简单的矩形或者圆形时可以直接使用CGPath。但是当需要一些复杂的形状的时候,比如圆角矩形 或者 五角星之类的 ,我们可以使用 UIBezierPath ,它是 UIKit 提供的 objc 封装的CGPath 要简单的多。