CAReplicatorLayer

CAReplicatorLayer的目的是为了高效生成许多相似的图层。它会绘制一个或多个图层的子图层,并在每个复制体上应用不同的变换。看上去演示能够更加解释这些,我们来写个例子吧。

重复图层(Repeating Layers)

清单6.8中,我们在屏幕的中间创建了一个小白色方块图层,然后用CAReplicatorLayer生成十个图层组成一个圆圈。instanceCount属性指定了图层需要重复多少次。instanceTransform指定了一个CATransform3D3D变换(这种情况下,下一图层的位移和旋转将会移动到圆圈的下一个点)。

变换是逐步增加的,每个实例都是相对于前一实例布局。这就是为什么这些复制体最终不会出现在同意位置上,图6.8是代码运行结果。

清单6.8 用CAReplicatorLayer重复图层

  1. @interface ViewController ()
  2. @property (nonatomic, weak) IBOutlet UIView *containerView;
  3. @end
  4. @implementation ViewController
  5. - (void)viewDidLoad
  6. {
  7. [super viewDidLoad];
  8. //create a replicator layer and add it to our view
  9. CAReplicatorLayer *replicator = [CAReplicatorLayer layer];
  10. replicator.frame = self.containerView.bounds;
  11. [self.containerView.layer addSublayer:replicator];
  12. //configure the replicator
  13. replicator.instanceCount = 10;
  14. //apply a transform for each instance
  15. CATransform3D transform = CATransform3DIdentity;
  16. transform = CATransform3DTranslate(transform, 0, 200, 0);
  17. transform = CATransform3DRotate(transform, M_PI / 5.0, 0, 0, 1);
  18. transform = CATransform3DTranslate(transform, 0, -200, 0);
  19. replicator.instanceTransform = transform;
  20. //apply a color shift for each instance
  21. replicator.instanceBlueOffset = -0.1;
  22. replicator.instanceGreenOffset = -0.1;
  23. //create a sublayer and place it inside the replicator
  24. CALayer *layer = [CALayer layer];
  25. layer.frame = CGRectMake(100.0f, 100.0f, 100.0f, 100.0f);
  26. layer.backgroundColor = [UIColor whiteColor].CGColor;
  27. [replicator addSublayer:layer];
  28. }
  29. @end

图6.8

图6.8 用CAReplicatorLayer创建一圈图层

注意到当图层在重复的时候,他们的颜色也在变化:这是用instanceBlueOffsetinstanceGreenOffset属性实现的。通过逐步减少蓝色和绿色通道,我们逐渐将图层颜色转换成了红色。这个复制效果看起来很酷,但是CAReplicatorLayer真正应用到实际程序上的场景比如:一个游戏中导弹的轨迹云,或者粒子爆炸(尽管iOS 5已经引入了CAEmitterLayer,它更适合创建任意的粒子效果)。除此之外,还有一个实际应用是:反射。

反射

使用CAReplicatorLayer并应用一个负比例变换于一个复制图层,你就可以创建指定视图(或整个视图层次)内容的镜像图片,这样就创建了一个实时的『反射』效果。让我们来尝试实现这个创意:指定一个继承于UIViewReflectionView,它会自动产生内容的反射效果。实现这个效果的代码很简单(见清单6.9),实际上用ReflectionView实现这个效果会更简单,我们只需要把ReflectionView的实例放置于Interface Builder(见图6.9),它就会实时生成子视图的反射,而不需要别的代码(见图6.10).

清单6.9 用CAReplicatorLayer自动绘制反射

  1. #import "ReflectionView.h"
  2. #import <QuartzCore/QuartzCore.h>
  3. @implementation ReflectionView
  4. + (Class)layerClass
  5. {
  6. return [CAReplicatorLayer class];
  7. }
  8. - (void)setUp
  9. {
  10. //configure replicator
  11. CAReplicatorLayer *layer = (CAReplicatorLayer *)self.layer;
  12. layer.instanceCount = 2;
  13. //move reflection instance below original and flip vertically
  14. CATransform3D transform = CATransform3DIdentity;
  15. CGFloat verticalOffset = self.bounds.size.height + 2;
  16. transform = CATransform3DTranslate(transform, 0, verticalOffset, 0);
  17. transform = CATransform3DScale(transform, 1, -1, 0);
  18. layer.instanceTransform = transform;
  19. //reduce alpha of reflection layer
  20. layer.instanceAlphaOffset = -0.6;
  21. }
  22. - (id)initWithFrame:(CGRect)frame
  23. {
  24. //this is called when view is created in code
  25. if ((self = [super initWithFrame:frame])) {
  26. [self setUp];
  27. }
  28. return self;
  29. }
  30. - (void)awakeFromNib
  31. {
  32. //this is called when view is created from a nib
  33. [self setUp];
  34. }
  35. @end

图6.9

图6.9 在Interface Builder中使用ReflectionView

图6.10

图6.10 ReflectionView自动实时产生反射效果。

开源代码ReflectionView完成了一个自适应的渐变淡出效果(用CAGradientLayer和图层蒙板实现),代码见 https://github.com/nicklockwood/ReflectionView