# 組透明
????UIView有一個叫做`alpha`的屬性來確定視圖的透明度。CALayer有一個等同的屬性叫做`opacity`,這兩個屬性都是影響子層級的。也就是說,如果你給一個圖層設置了`opacity`屬性,那它的子圖層都會受此影響。
????iOS常見的做法是把一個控件的alpha值設置為0.5(50%)以使其看上去呈現為不可用狀態。對于獨立的視圖來說還不錯,但是當一個控件有子視圖的時候就有點奇怪了,圖4.20展示了一個內嵌了UILabel的自定義UIButton;左邊是一個不透明的按鈕,右邊是50%透明度的相同按鈕。我們可以注意到,里面的標簽的輪廓跟按鈕的背景很不搭調。

圖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
~~~

圖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 總結