iOS Uiview Subclass, Draw See-Through Text to Background

UIView subclass draws background despite completely empty drawRect: - why?

Sorry for this monologue. :)

The thing is that the UIView's layer apparently draws the background, which is independent from drawRect:. This is why you can't get rid of the background by overriding drawRect:.

You can either override - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx and make the layer draw whatever you want, or you override - (void) setBackgroundColor:(UIColor *)newColor and don't assign newColor to backgroundColor, but to your own ivar, like myBackgroundColor. You can then use myBackgroundColor in drawRect; to draw the background however you like.


Overriding setBackgroundColor:

Define an instance variable to hold your background color, e.g. myBackgroundColor. In your init methods, set the real background color to be the clearColor:

- (id) initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super init...])) {
[super setBackgroundColor:[UIColor clearColor]];
}
return self;
}

Override:

- (void) setBackgroundColor:(UIColor *)newColor
{
if (newColor != myBackgroundColor) {
[myBackgroundColor release];
myBackgroundColor = [newColor retain];
}
}

Then use myBackgroundColor in your drawRect: method. This way you can use the color assigned from Interface Builder (or Xcode4) in your code.

How do I create a UIView subclass with a transparent gradient background?

I wouldn't bother with CoreGraphics so I would use CAGradientLayer.

  1. Override +layerClass in your subclass.

    + (Class)layerClass {
    return [CAGradientLayer class];
    }
  2. Redefine layer property in interface to use this class.

    @property(nonatomic, readonly, retain) CAGradientLayer *layer;
  3. Set the colors and other attributes.

    self.layer.colors = gradientColors;
    self.layer.locations = gradientLocations; // But this time as `NSArray`
    self.layer.startPoint = startPoint; // From 0 to 1
    self.layer.endPoint = endPoint; // From 0 to 1

Having UIView drawRect occur in a background thread

Yes it is possible. You will probably need to generate the content view as an image in the background and push the images into a nsdictionary or array.

So while your background is generating the images you can just show the image in drawrect function by rendering the image, providing the image has been generated.

A WWDC video that shows how to do it: WWDC 2012 session 211 - Building Concurrent User Interfaces on IOS. Here is the video description:

For a great user experience, it's essential to keep your application responsive while it renders complex UI elements and processes data. Learn how to use concurrency at the UIKit layer to perform drawing and other common operations without blocking user interaction.

Render Transparent Text in a Colored Background

Normally, setting the color to clear and drawing the text would result in no visible effect. But if you first use CGContextSetBlendMode with kCGBlendModeCopy, it should completely replace the (colored) pixels in View2's background with the transparent color you set when drawing the text.

Why can't you change a UIView background color in drawRect?

If you set backgroundColor when the view is first configured (i.e., before the OS calls drawRect), that backgroundColor will be used without any further code on your part. As the UIView Class Reference says, the backgroundColor property is used to "set the view’s color rather than drawing that color yourself."

But if you attempt to set it in drawRect, the background fill has already been performed, so you won't immediately see the effect of changing the background color (unless you manually perform another fill yourself in drawRect). The drawRect method should be used for rendering the view, not for configuring it.

If the UIView sets the backgroundColor as the view is being configured (e.g. in whichever init method you avail yourself of), that background color will used, without any need to do anything else in drawRect.

drawRect drawing 'transparent' text?

I've rewritten it as a UILabel subclass using barely any code and posted it on GitHub

The gist of it is you override drawRect but call [super drawRect:rect] to let the UILabel render as normal. Using a white label color lets you easily use the label itself as a mask.

- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();

// let the superclass draw the label normally
[super drawRect:rect];

CGContextConcatCTM(context, CGAffineTransformMake(1, 0, 0, -1, 0, CGRectGetHeight(rect)));

// create a mask from the normally rendered text
CGImageRef image = CGBitmapContextCreateImage(context);
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerComponent(image), CGImageGetBitsPerPixel(image), CGImageGetBytesPerRow(image), CGImageGetDataProvider(image), CGImageGetDecode(image), CGImageGetShouldInterpolate(image));

CFRelease(image); image = NULL;

// wipe the slate clean
CGContextClearRect(context, rect);

CGContextSaveGState(context);
CGContextClipToMask(context, rect, mask);

CFRelease(mask); mask = NULL;

[self RS_drawBackgroundInRect:rect];

CGContextRestoreGState(context);

}


Related Topics



Leave a reply



Submit