drawRect drawing 'transparent' text?

前端 未结 3 625
北荒
北荒 2020-12-23 18:32

I am looking to draw a UILabel (preferable through subclassing) as a transparent label, but with solid background. I draw up an quick example (sorry, it\'s ugly, but it gets

3条回答
  •  梦毁少年i
    2020-12-23 18:52

    Here's a technique that's similar to Matt Gallagher's, which will generate an inverted text mask with an image.

    Allocate a (mutable) data buffer. Create a bitmap context with an 8-bit alpha channel. Configure settings for text drawing. Fill the whole buffer in copy mode (default colour assumed to have alpha value of 1). Write the text in clear mode (alpha value of 0). Create an image from the bitmap context. Use the bitmap as a mask to make a new image from the source image. Create a new UIImage and clean up.

    Every time the textString or sourceImage or size values change, re-generate the final image.

    CGSize size = /* assume this exists */;
    UIImage *sourceImage = /* assume this exists */;
    NSString *textString = /* assume this exists */;
    char *text = [textString cStringUsingEncoding:NSMacOSRomanStringEncoding];
    NSUInteger len = [textString lengthOfBytesUsingEncoding:cStringUsingEncoding:NSMacOSRomanStringEncoding];
    
    NSMutableData *data = [NSMutableData dataWithLength:size.width*size.height*1];
    CGContextRef context = CGBitmapContextCreate([data mutableBytes], size.width, size.height, 8, size.width, NULL, kCGImageAlphaOnly);
    
    CGContextSelectFont(context, "Gill Sans Bold", 64.0f, kCGEncodingMacRoman);
    CGContextSetTextDrawingMode(context, kCGTextFill);
    
    CGContextSetBlendMode(context, kCGBlendModeCopy);
    CGContextFillRect(context, overlay.bounds);
    CGContextSetBlendMode(context, kCGBlendModeClear);
    CGContextShowTextAtPoint(context, 16.0f, 16.0f, text, len);
    
    CGImageRef textImage = CGBitmapContextCreateImage(context);
    CGImageRef newImage = CGImageCreateWithMask(sourceImage.CGImage, textImage);
    
    UIImage *finalImage = [UIImage imageWithCGImage:newImage];
    
    CGContextRelease(context);
    CFRelease(newImage);
    CFRelease(textImage);
    

    Another way to do this involves putting the textImage into a new layer and setting that layer on your view's layer. (Remove the lines that create "newImage" and "finalImage".) Assuming this happens inside your view's code somewhere:

    CALayer *maskLayer = [[CALayer alloc] init];
    CGPoint position = CGPointZero;
    
    // layout the new layer
    position = overlay.layer.position;
    position.y *= 0.5f;
    maskLayer.bounds = overlay.layer.bounds;
    maskLayer.position = position;
    maskLayer.contents = (__bridge id)textImage;
    
    self.layer.mask = maskLayer;
    

    There are more alternatives, some might be better (subclass UIImage and draw the text directly in clear mode after the superclass has done its drawing?).

提交回复
热议问题