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
.
Override
+layerClass
in your subclass.+ (Class)layerClass {
return [CAGradientLayer class];
}Redefine
layer
property in interface to use this class.@property(nonatomic, readonly, retain) CAGradientLayer *layer;
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
How to Implement Two Inits with Same Content Without Code Duplication in Swift
Phonegap iOS 5.1 and Localstorage
How to Retrieve Keystrokes from a Custom Keyboard on an iOS App
Save iOS 8 Documents to Icloud Drive
File Was Built for Archive Which Is Not the Architecture Being Linked (I386)
Class Is Implemented in Both. One of the Two Will Be Used
Wait for Asynchronous Operation to Complete in Swift
Avaudioplayer Throws Breakpoint in Debug Mode
iOS 7.1 Uitextview Still Not Scrolling to Cursor/Caret After New Line
How to Use Static Cells in Uitableview Without Using Storyboards
How to Do Programmatically Gradient Border Color Uibutton with Swift
Running Individual Xctest (Ui, Unit) Test Cases for iOS Apps from the Command Line
Showing the File Download Progress with Nsurlsessiondatatask
Why Can't I Force Landscape Orientation When Use Uinavigationcontroller
Find List of Local Notification the App Has Already Set