CAReplicatorLayer CAReplicatorLayer的目的是為了高效生成許多相似的圖層。它會繪製一個或多個圖層的子圖層,併在每個複製體上應用不同的變換。看上去演示能夠更加解釋這些,我們來寫個例子吧。 重覆圖層(Repeating Layers) 清單6.8中,我們在屏幕的中間創建了 ...
CAReplicatorLayer
CAReplicatorLayer
的目的是為了高效生成許多相似的圖層。它會繪製一個或多個圖層的子圖層,併在每個複製體上應用不同的變換。看上去演示能夠更加解釋這些,我們來寫個例子吧。
重覆圖層(Repeating Layers)
清單6.8中,我們在屏幕的中間創建了一個小白色方塊圖層,然後用CAReplicatorLayer
生成十個圖層組成一個圓圈。instanceCount
屬性指定了圖層需要重覆多少次。instanceTransform
指定了一個CATransform3D
3D變換(這種情況下,下一圖層的位移和旋轉將會移動到圓圈的下一個點)。
變換是逐步增加的,每個實例都是相對於前一實例佈局。這就是為什麼這些複製體最終不會出現在同意位置上,圖6.8是代碼運行結果。
清單6.8 用CAReplicatorLayer
重覆圖層
1 @interface ViewController () 2 3 @property (nonatomic, weak) IBOutlet UIView *containerView; 4 5 @end 6 7 @implementation ViewController 8 - (void)viewDidLoad 9 { 10 [super viewDidLoad]; 11 //create a replicator layer and add it to our view 12 CAReplicatorLayer *replicator = [CAReplicatorLayer layer]; 13 replicator.frame = self.containerView.bounds; 14 [self.containerView.layer addSublayer:replicator]; 15 16 //configure the replicator 17 replicator.instanceCount = 10; 18 19 //apply a transform for each instance 20 CATransform3D transform = CATransform3DIdentity; 21 transform = CATransform3DTranslate(transform, 0, 200, 0); 22 transform = CATransform3DRotate(transform, M_PI / 5.0, 0, 0, 1); 23 transform = CATransform3DTranslate(transform, 0, -200, 0); 24 replicator.instanceTransform = transform; 25 26 //apply a color shift for each instance 27 replicator.instanceBlueOffset = -0.1; 28 replicator.instanceGreenOffset = -0.1; 29 30 //create a sublayer and place it inside the replicator 31 CALayer *layer = [CALayer layer]; 32 layer.frame = CGRectMake(100.0f, 100.0f, 100.0f, 100.0f); 33 layer.backgroundColor = [UIColor whiteColor].CGColor; 34 [replicator addSublayer:layer]; 35 } 36 @endView Code
Swift 3.0 代碼
1 // CAReplicatorLayer 2 private lazy var replicatorView: UIView! = UIView() 3 4 func replicatorLayerOfView() { 5 self.view.addSubview(self.replicatorView) 6 let replicator = CAReplicatorLayer() 7 replicator.frame = CGRect(x: 0, y: 0, width: 30, height: 30) 8 self.replicatorView.layer.addSublayer(replicator) 9 10 replicator.instanceCount = 10 11 12 var transform = CATransform3DIdentity 13 transform = CATransform3DTranslate(transform, 0, 200, 0) 14 transform = CATransform3DRotate(transform, .pi / 5.0, 0, 0, 1) 15 transform = CATransform3DTranslate(transform, 0, -200, 0) 16 replicator.instanceTransform = transform 17 18 replicator.instanceBlueOffset = -0.1 19 replicator.instanceGreenOffset = -0.1 20 21 let layer = CALayer() 22 layer.frame = CGRect(x: 30, y: 30, width: 30, height: 30) 23 layer.backgroundColor = UIColor.white.cgColor 24 replicator.addSublayer(layer) 25 26 self.replicatorView.snp.makeConstraints { (make) in 27 make.top.equalTo(self.gradientView) 28 make.size.equalTo(self.gradientView) 29 make.left.equalTo(self.gradientView.snp.right).inset(-10) 30 } 31 32 }View Code
圖6.8 用CAReplicatorLayer
創建一圈圖層
註意到當圖層在重覆的時候,他們的顏色也在變化:這是用instanceBlueOffset
和instanceGreenOffset
屬性實現的。通過逐步減少藍色和綠色通道,我們逐漸將圖層顏色轉換成了紅色。這個複製效果看起來很酷,但是CAReplicatorLayer
真正應用到實際程式上的場景比如:一個游戲中導彈的軌跡雲,或者粒子爆炸(儘管iOS 5已經引入了CAEmitterLayer
,它更適合創建任意的粒子效果)。除此之外,還有一個實際應用是:反射。
反射
使用CAReplicatorLayer
並應用一個負比例變換於一個複製圖層,你就可以創建指定視圖(或整個視圖層次)內容的鏡像圖片,這樣就創建了一個實時的『反射』效果。讓我們來嘗試實現這個創意:指定一個繼承於UIView
的ReflectionView
,它會自動產生內容的反射效果。實現這個效果的代碼很簡單(見清單6.9),實際上用ReflectionView
實現這個效果會更簡單,我們只需要把ReflectionView
的實例放置於Interface Builder(見圖6.9),它就會實時生成子視圖的反射,而不需要別的代碼(見圖6.10).
清單6.9 用CAReplicatorLayer
自動繪製反射
1 #import "ReflectionView.h" 2 #import 3 4 @implementation ReflectionView 5 6 + (Class)layerClass 7 { 8 return [CAReplicatorLayer class]; 9 } 10 11 - (void)setUp 12 { 13 //configure replicator 14 CAReplicatorLayer *layer = (CAReplicatorLayer *)self.layer; 15 layer.instanceCount = 2; 16 17 //move reflection instance below original and flip vertically 18 CATransform3D transform = CATransform3DIdentity; 19 CGFloat verticalOffset = self.bounds.size.height + 2; 20 transform = CATransform3DTranslate(transform, 0, verticalOffset, 0); 21 transform = CATransform3DScale(transform, 1, -1, 0); 22 layer.instanceTransform = transform; 23 24 //reduce alpha of reflection layer 25 layer.instanceAlphaOffset = -0.6; 26 } 27  28 - (id)initWithFrame:(CGRect)frame 29 { 30 //this is called when view is created in code 31 if ((self = [super initWithFrame:frame])) { 32 [self setUp]; 33 } 34 return self; 35 } 36 37 - (void)awakeFromNib 38 { 39 //this is called when view is created from a nib 40 [self setUp]; 41 } 42 @endView Code