iosuiviewcore-animationcalayerdrawrect

iOS Custom UIView Drawing - CAShapeLayers or drawRect?


I'm new to iOS UIView drawing and I'm really trying to implement a custom UIView class in a standard way.

The UIView class that I'm working on now is simple: it has mostly static background shapes that form a composite shape. I also want to add animation to this UIView class so that a simple shape can animate its path on top of the static shapes.

How I'm currently implementing this

Right now, I'm implementing the static drawing in the drawRect: method of the UIView subclass. This works fine. I also have not implemented animation of the single shape yet.

What I'm looking to have answered

Question 1:

Is it better to have the static shapes drawn in the drawRect: method as I'm currently doing it, or is there a benefit to refactoring all of the shapes being drawn into class-extension-scoped CAShapeLayer properties and doing something like:

-(instancetype) initWithFrame:(CGRect) frame
{
   if (self = [super initWithFrame:frame])
   {
      [self setupView];
   }

   return self;
}

-(void) setupView // Allocate, init, and setup one-time layer properties like fill colorse.
{
   self.shapeLayer1 = [CAShapeLayer layer];
   [self.layer addSubLayer:shapeLayer1];
   self.shapeLayer2 = [CAShapeLayer layer];
   [self.layer addSubLayer:shapeLayer2];
   // ... and so on
}

-(void) layoutSubviews // Set frames and paths of shape layers here.
{
    self.shapeLayer1.frame = self.bounds;
    self.shapeLayer2.frame = self.bounds;

    self.shapeLayer1.path = [UIBezierPath somePath].CGPath;
    self.shapeLayer2.path = [UIBezierPath somePath].CGPath;
}

Question 2: Regardless of whether I implement the static shapes as CAShapeLayers or in drawRect:, is the best way to implement an animatable shape for this UIView a CAShapeLayer property that is implemented as the other CAShapeLayers would be implemented above? Creating a whole separate UIView class just for one animated shape and adding it as a subview to this view seems silly, so I'm thinking that a CAShapeLayer is the way to go to accomplish that.

I would appreciate any help with this very much!


Solution

  • You could do it either way, but using shape layers for everything would probably be cleaner and faster. Shape layers have built-in animation support using Core Animation.

    It's typically faster to avoid implementing drawRect and instead let the system draw for you.

    Edit:

    I would actually word this more strongly than I did in 2014. The underlying drawing engine in iOS is optimized for tiled rendering using layers. You will get better performance and smoother animation by using CALayers and CAAnimation (or higher level UIView or SwiftUI animation which is built on CAAnimation.)