title: Draw triangle cutout for selection indication in UIView
body: <p>I'm creating a view that serves as a category selector for my app. I'd like it to have a cutout triangle as the selection indication, as in this image:</p>
  
  <p><img src="https://i.stack.imgur.com/WTNBS.png" alt="Custom UI design"></p>
  
  <p>I'm not sure how to draw the triangle so that it is a cutout, revealing the main view underneath. The main view underneath will most likely have a custom, possibly non-repeating (I haven't decided yet) image as its background. In addition, I would like the triangle to animate to a new location when the selection changes, which further complicates things a bit.</p>
  
  <p>I realize a subview would make the animation easier, but would complicate the drawing; direct drawing would probably make the animation a bit harder. And I'm not too familiar with Quartz, so I'm not sure how to go with the direct drawing route.</p>
  
  <p>Thanks in advance!</p>
  
  <p><strong>Update:</strong> I've looked at Matt Gallagher's post on <a href="http://cocoawithlove.com/2010/05/5-ways-to-draw-2d-shape-with-hole-in.html" rel="nofollow noreferrer">drawing shapes with holes</a>, but it doesn't really answer my question. Is there a way for me to "see" what's underneath a certain path within my shape, and copy that? …And then support animating it?</p>
  
  <p><strong>Update 2:</strong> I've done a partial job by simply drawing an additional path. The result looks like this:
  <a href="http://dl.dropbox.com/u/7828009/Category%20Selector.mov" rel="nofollow noreferrer">http://dl.dropbox.com/u/7828009/Category%20Selector.mov</a></p>
  
  <p>The code:</p>
  
  <pre><code>CGRect cellRect = [self rectForCategoryNumber:(selectedCategoryIndex + 1)];
  [[UIColor scrollViewTexturedBackgroundColor] setFill];
  CGContextMoveToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.15));
  CGContextAddLineToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.65));
  CGContextAddLineToPoint(currentContext, self.frame.size.width * 0.8, (cellRect.origin.y + cellRect.size.height * 0.4));
  CGContextClosePath(currentContext);
  CGContextFillPath(currentContext);
  [[UIColor darkGrayColor] setStroke];
  CGContextSetLineCap(currentContext, kCGLineCapRound);
  CGContextMoveToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.15));
  CGContextAddLineToPoint(currentContext, self.frame.size.width * 0.8, (cellRect.origin.y + cellRect.size.height * 0.4));
  CGContextSetLineWidth(currentContext, 2.5);
  CGContextStrokePath(currentContext);
  [[UIColor lightGrayColor] setStroke];
  CGContextMoveToPoint(currentContext,self.frame.size.width * 0.8, (cellRect.origin.y + cellRect.size.height * 0.4));
  CGContextAddLineToPoint(currentContext, self.frame.size.width, (cellRect.origin.y + cellRect.size.height * 0.65));
  CGContextSetLineWidth(currentContext, 1.0);
  CGContextStrokePath(currentContext);
  </code></pre>
  
  <p>Obviously, in this case it only works because I'm using the same fill color in both cases; I'd like to eliminate this dependency if possible. Also, of course I'd like to animate the position of that triangle.</p>
  
  <p><strong>Update 3:</strong> What I tried to do to animate:</p>
  
  <pre><code>static CALayer *previousLayer = nil;
  static CGMutablePathRef previousPath = nil;
  // … Get context, etc.
  CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
  shapeLayer.path = shapePath;
  [shapeLayer setFillColor:[[UIColor redColor] CGColor]];
  [shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]];
  [shapeLayer setBounds:self.bounds];
  [shapeLayer setAnchorPoint:self.bounds.origin];
  [shapeLayer setPosition:self.bounds.origin];
  if (previousPath) {     // Animate change
      CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"changePath"];
      animation.duration = 0.5;
      animation.fromValue = (id)previousPath;
      animation.toValue = (id)shapePath;
      [shapeLayer addAnimation:animation forKey:@"animatePath"];
      previousPath = shapePath;
  }
  
  if (previousLayer)
      [previousLayer removeFromSuperlayer];
  previousLayer = shapeLayer;
  [self.layer addSublayer:shapeLayer];
  </code></pre>