# 组透明
UIView有一个叫做`alpha`的属性来确定视图的透明度。CALayer有一个等同的属性叫做`opacity`,这两个属性都是影响子层级的。也就是说,如果你给一个图层设置了`opacity`属性,那它的子图层都会受此影响。
iOS常见的做法是把一个控件的alpha值设置为0.5(50%)以使其看上去呈现为不可用状态。对于独立的视图来说还不错,但是当一个控件有子视图的时候就有点奇怪了,图4.20展示了一个内嵌了UILabel的自定义UIButton;左边是一个不透明的按钮,右边是50%透明度的相同按钮。我们可以注意到,里面的标签的轮廓跟按钮的背景很不搭调。
![](https://box.kancloud.cn/2015-12-24_567bc1f64ffc2.png)
图4.20 右边的渐隐按钮中,里面的标签清晰可见
这是由透明度的混合叠加造成的,当你显示一个50%透明度的图层时,图层的每个像素都会一半显示自己的颜色,另一半显示图层下面的颜色。这是正常的透明度的表现。但是如果图层包含一个同样显示50%透明的子图层时,你所看到的视图,50%来自子视图,25%来了图层本身的颜色,另外的25%则来自背景色。
在我们的示例中,按钮和表情都是白色背景。虽然他们都是50%的可见度,但是合起来的可见度是75%,所以标签所在的区域看上去就没有周围的部分那么透明。所以看上去子视图就高亮了,使得这个显示效果都糟透了。
理想状况下,当你设置了一个图层的透明度,你希望它包含的整个图层树像一个整体一样的透明效果。你可以通过设置Info.plist文件中的`UIViewGroupOpacity`为YES来达到这个效果,但是这个设置会影响到这个应用,整个app可能会受到不良影响。如果`UIViewGroupOpacity`并未设置,iOS 6和以前的版本会默认为NO(也许以后的版本会有一些改变)。
另一个方法就是,你可以设置CALayer的一个叫做`shouldRasterize`属性(见清单4.7)来实现组透明的效果,如果它被设置为YES,在应用透明度之前,图层及其子图层都会被整合成一个整体的图片,这样就没有透明度混合的问题了(如图4.21)。
为了启用`shouldRasterize`属性,我们设置了图层的`rasterizationScale`属性。默认情况下,所有图层拉伸都是1.0, 所以如果你使用了`shouldRasterize`属性,你就要确保你设置了`rasterizationScale`属性去匹配屏幕,以防止出现Retina屏幕像素化的问题。
当`shouldRasterize`和`UIViewGroupOpacity`一起的时候,性能问题就出现了(我们在第12章『速度』和第15章『图层性能』将做出介绍),但是性能碰撞都本地化了(译者注:这句话需要再翻译)。
清单4.7 使用`shouldRasterize`属性解决组透明问题
~~~
@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
~~~
![](https://box.kancloud.cn/2015-12-24_567bc1f66e58d.png)
图4.21 修正后的图
- Introduction
- 1. 图层树
- 1.1 图层与视图
- 1.2 图层的能力
- 1.3 使用图层
- 1.4 总结
- 2. 寄宿图
- 2.1 contents属性
- 2.2 Custom Drawing
- 2.3 总结
- 3. 图层几何学
- 3.1 布局
- 3.2 锚点
- 3.3 坐标系
- 3.4 Hit Testing
- 3.5 自动布局
- 3.6 总结
- 4. 视觉效果
- 4.1 圆角
- 4.2 图层边框
- 4.3 阴影
- 4.4 图层蒙板
- 4.5 拉伸过滤
- 4.6 组透明
- 4.7 总结
- 5. 变换
- 5.1 仿射变换
- 5.2 3D变换
- 5.3 固体对象
- 5.4 总结
- 6. 专用图层
- 6.1 CAShapeLayer
- 6.2 CATextLayer
- 6.3 CATransformLayer
- 6.4 CAGradientLayer
- 6.5 CAReplicatorLayer
- 6.6 CAScrollLayer
- 6.7 CATiledLayer
- 6.8 CAEmitterLayer
- 6.9 CAEAGLLayer
- 6.10 AVPlayerLayer
- 6.11 总结
- 7. 隐式动画
- 7.1 事务
- 7.2 完成块
- 7.3 图层行为
- 7.4 呈现与模型
- 7.5 总结
- 8. 显式动画
- 8.1 属性动画
- 8.2 动画组
- 8.3 过渡
- 8.4 在动画过程中取消动画
- 8.5 总结
- 9. 图层时间
- 9.1 CAMediaTiming协议
- 9.2 层级关系时间
- 9.3 手动动画
- 9.4 总结
- 10. 缓冲
- 10.1 动画速度
- 10.2 自定义缓冲函数
- 10.3 总结
- 11. 基于定时器的动画
- 11.1 定时帧
- 11.2 物理模拟
- 12. 性能调优
- 12.1. CPU VS GPU
- 12.2 测量,而不是猜测
- 12.3 Instruments
- 12.4 总结
- 13. 高效绘图
- 13.1 软件绘图
- 13.2 矢量图形
- 13.3 脏矩形
- 13.4 异步绘制
- 13.5 总结
- 14. 图像IO
- 14.1 加载和潜伏
- 14.2 缓存
- 14.3 文件格式
- 14.4 总结
- 15. 图层性能
- 15.1 隐式绘制
- 15.2 离屏渲染
- 15.3 混合和过度绘制
- 15.4 减少图层数量
- 15.5 总结