Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I want to draw text onto my subclass on UIView so that the text is cut out of the shape and the background behind the view shows through, just like in the OSX Mavericks logo found here.

I would say that I'm more of an intermediate/early advanced iOS developer so feel free to throw some crazy solutions at me. I'd expect I'd have to override drawRect in order to do this.

Thanks guys!

EDIT:

I should mention that my first attempt was making the text [UIColor clearColor] which didn't work since that just set the alpha component of the text to 0, which just showed the view through the text.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
436 views
Welcome To Ask or Share your Answers For Others

1 Answer

Disclaimer: I'm writing this without testing, so forgive me if I'm wrong here.

You should achieve what you need by these two steps:

  1. Create a CATextLayer with the size of your view, set the backgroundColor to be fully transparent and foregroundColor to be opaque (by [UIColor colorWithWhite:0 alpha:1] and [UIColor colorWithWhite:0 alpha:0]. Then set the string property to the string you want to render, font and fontSize etc.

  2. Set your view's layer's mask to this layer: myView.layer.mask = textLayer. You'll have to import QuartzCore to access the CALayer of your view.

Note that it's possible that I switched between the opaque and transparent color in the first step.

Edit: Indeed, Noah was right. To overcome this, I used CoreGraphics with the kCGBlendModeDestinationOut blend mode.

First, a sample view that shows that it indeed works:

@implementation TestView

- (id)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    self.backgroundColor = [UIColor clearColor];
  }
  return self;
}

- (void)drawRect:(CGRect)rect {
  [[UIColor redColor] setFill];
  UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:10];
  [path fill];

  CGContextRef context = UIGraphicsGetCurrentContext();
  CGContextSaveGState(context); {
    CGContextSetBlendMode(context, kCGBlendModeDestinationOut);
    [@"Hello!" drawAtPoint:CGPointZero withFont:[UIFont systemFontOfSize:24]];
  } CGContextRestoreGState(context);
}

@end

After adding this to your view controller, you'll see the view behind TestView where Hello! is drawn.

Why does this work:

The blend mode is defined as R = D*(1 - Sa), meaning we need opposite alpha values than in the mask layer I suggested earlier. Therefore, all you need to do is to draw with an opaque color and this will be subtracted from the stuff you've drawn on the view beforehand.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...