Background:
I have a subclass of UITableViewCell whose layout is defined as a prototype cell in a storyboard. One of the cell's IBOutlets is a subclass of UIView I made called BorderedProfileImageView. This class's drawRect: function is overridden as follows:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]);
CGContextSetLineWidth(context, 1.f);
CGFloat halfWidth = self.bounds.size.width/2;
NSInteger radius = sqrt(pow(halfWidth, 2) + pow(halfWidth, 2)) - 8.5;
CGContextAddArc(context,self.bounds.size.width/2,self.bounds.size.height/2,radius,0,2*3.1415926535898,1);
CGContextStrokePath(context);
}
This adds a blue ring to the UIView.
Problem:
The blue ring never appears, and BorderdProfileImageView's drawRect: function never gets called. The cell still draws, the UIImageView which is inside the BorderdProfileImageView gets drawn. I do call setNeedsDisplay on the BorderedProfileImageView when setting up the cell.
Why is drawRect: not getting called?
I figured it out.
The object in IB which was set to the BorderedProfileImageView was originally a UIImageView. Changing this object to a UIView and re-linking has resulted in the desired behavior.
Related
I have some code in separate class, who bounded with UIView.
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect drawRect = CGRectMake(20, 262, 139, 169);
[self setFrame:drawRect];
CGContextSetLineWidth(context, 2);
CGContextSetStrokeColorWithColor(context, [[UIColor colorWithRed:125.0f/255.0f green:251.0f/255.0f blue:181.0f/255.0f alpha:1] CGColor]);
CGContextSetRGBFillColor(context, 200.0f/255.0f, 100.0f/255.0f, 100.0f/255.0f, 1.0f);
CGContextFillRect(context, drawRect);
But after clicking this view, size of UIView resizes to dimensions from interface builder model from my storyboard.
What does matter, and what's wrong with it?
drawRect: is not the place to change the frame. If the system can't automatically handle resizing the frame (by scaling the view, for instance), then drawRect: is called in response to resizing the frame. If you could change the frame size in the middle of drawing, you'd have an infinite loop.
If you want the view to be in the rectangle (20,262,139,169), then that's simple to put in autolayout. Just put the view where you want it, and create constraints to keep it there using Interface Builder.
If you don't want autolayout (not sure why you'd want to turn it off here, but if you did), you can turn it off and call setFrame: in viewDidLoad. But there's no reason to call it again in drawRect:.
I'm working with autolayout and I have a RoundView class (subview of UIButton) which drawRect method is:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat lineWidth = 0.0;
CGContextSetLineWidth(context, lineWidth);
CGContextSetFillColorWithColor(context, _currentBackgroundColor.CGColor);
CGContextAddEllipseInRect(context, self.bounds);
CGContextFillPath(context);
}
Then I add it to self (a UIView), set its width and height using autolayout. Everything looks great.
But when I change its size constraints (to have a bigger view), and call
[self layoutIfNeeded];
in an animation block, the circle pixels look bigger and ugly.
Do I do this the correct way ?
I just got it from this post !
The problem was that the os wasn't calling drawRect at each animation step.
To force it, in RoundView's init:
self.contentMode = UIViewContentModeRedraw;
You need to take the content scale into account for the retina displays [UIDevice mainScreen].scale. See answers to this (question)[CGContext and retina display
I have a ViewController on storyboard. I have used the interface builder to set a toolbar at the bottom of the screen. I have set the custom view to a view overrides drawRect. However, for the life of me, I cannot get anything ever to show up on screen called from that drawRect. drawRect itself is called just fine, but nothing shows up on screen.
Also, I have this ViewController with a method that uses AVCaptureSession to toggle its background to a live view from camera input. I had suspected that this might have been the cause for error, but after removing all references of AVCaptureSession, I still cannot get this to work.
Sorry for my writing and/or lack of logic, I don't have any sleep right now.
Edit: Here is a small example of code that won't work. Every method inside gets called, but nothing is to show.
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
CGContextMoveToPoint(context, 0,0); //start at this point
CGContextAddLineToPoint(context, 100, 100); //draw to this point
// and now draw the Path!
CGContextStrokePath(context);
}
The documentation for UIView says to not call [super drawRect] if you're overriding UIView. Remove that call! It's been known to cause strange behaviour.
According to the docs:
If you subclass UIView directly, your implementation of this method
does not need to call super. However, if you are subclassing a
different view class, you should call super at some point in your
implementation.
I have a UIView where I would like to draw a Circle that extends past the frame of the UIView,
I have set the masksToBounds to NO - expecting that I can draw past outside the bounds of the UIView by 5 pixels on the right and bottom.
I expect the oval to not get clipped but it does get clipped and does not draw outside the bounds?
- (void)drawRect:(CGRect)rect
{
int width = self.bounds.size.width;
int height = self.bounds.size.height;
self.layer.masksToBounds = NO;
//// Rounded Rectangle Drawing
//// Oval Drawing
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0, 0, width+5, height+5)];
[[UIColor magentaColor] setFill];
[ovalPath fill];
[[UIColor blackColor] setStroke];
ovalPath.lineWidth = 1;
[ovalPath stroke];
}
From http://developer.apple.com/library/ios/#documentation/general/conceptual/Devpedia-CocoaApp/DrawingModel.html
UIView and NSView automatically configure the drawing environment of a
view before its drawRect: method is invoked. (In the AppKit framework,
configuring the drawing environment is called locking focus.) As part
of this configuration, the view class creates a graphics context for
the current drawing environment.
This graphics context is a Quartz object (CGContext) that contains
information the drawing system requires, such as the colors to apply,
the drawing mode (stroke or fill), line width and style information,
font information, and compositing options. (In the AppKit, an object
of the NSGraphicsContext class wraps a CGContext object.) A graphics
context object is associated with a window, bitmap, PDF file, or other
output device and maintains information about the current state of the
drawing environment for that entity. A view draws using a graphics
context associated with the view’s window. For a view, the graphics
context sets the default clipping region to coincide with the view’s
bounds and puts the default drawing origin at the origin of a view’s
boundaries.
Once the clipping region is set, you can only make it smaller. So, what you're trying to do isn't possible in a UIView drawRect:.
I'm not certain this will fix your problem, but it's something to look into. You're setting self.layer.masksToBounds = NO every single time you enter drawRect. You should try setting it inside the init method just once instead, A) because it's unnecessary to do it multiple times and B) because maybe there's a problem with setting it after drawRect has already been called--who knows.
I having some problems with drawRect and create a new instance of a UIView custom class.
My question is: How can i use of drawrect?
I created a UIViewController with a UIScrollView and inside this UIScrollView about 50 UIViews. Each UIView create inside 3 elements (Custom UIViews) each one with a drawrect:
- (void)drawRect:(CGRect)rect
{
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextClearRect(c, self.bounds);
CGContextSetStrokeColorWithColor(c, color.CGColor);
CGContextSetLineCap(c, kCGLineCapRound);
CGContextSetInterpolationQuality(c, kCGInterpolationHigh);
CGContextSetLineWidth(c, thickness);
CGContextAddArc(c, self.frame.size.width/2, self.frame.size.height/2, radius, angleIni*M_PI/180, angleEnd*M_PI/180, 0);
CGContextStrokePath(c);
}
At first it works like a charm, but when i try to remove this UIViewController and Create it again I'm getting a EXC_BAD_ACCESS.
If I remove the drawrect code everything begin to work again with no EXC_BAD_ACCESS. So I conclued tha my problem ismy drawrect method.
Is there some right way to true remove my UIviewController? On dealloc I'm removing all my UIViews inside UIScrollView and setting it to nil, besides I'm setting UIScrollView to nil too, like:
for (UIView *item in MyUICscrollView.subviews)
{
[item removeFromSuperview];
item = nil;
}
MyUICscrollView = nil;
Had someone the same issue?