I copied the code below from the Stanford ios7 course for adding a Bezier path to a view. however, when I included this code in ViewDidLoad it didn't show anything on the screen
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(75, 10)];
[path addLineToPoint: CGPointMake(160, 150)];
[path addLineToPoint:CGPointMake(10, 150)];
[[UIColor whiteColor] setStroke];
[[UIColor whiteColor] setFill];
[path stroke];
[path fill];
Afterwards, I added this log statement NSLog(#"path: %#", path); which prints this ominous error message.
This is a serious error. This application, or a library it uses, is
using an invalid context and is thereby contributing to an overall
degradation of system stability and reliability. This notice is a
courtesy: please fix this problem. It will become a fatal error in an
upcoming update.
Can you explain what I am doing wrong?
I have accomplished this by creating a CAShapeLayer, and adding it as a sublayer of the view's layer. What's neat is that you can use the UIBezierPath's CGPath attribute to set up the layer.
CAShapeLayer *layer = [CAShapeLayer layer];
layer.path = path.CGPath;
layer.strokeColor = [UIColor whiteColor].CGColor;
[self.view.layer addSublayer:layer];
The error message is exactly correct. You are using drawing commands, but you are not inside a drawing (graphics) context. Hence your commands are just thrown away (and are bad).
You should give drawing commands only when you are within a graphics context. There are two main such situations:
You're in a UIView subclass's drawRect:.
You've created an image graphics context with UIGraphicsBeginImageContextWithOptions.
You are in neither situation. You can make a bezier path object, constructing the path, but you cannot draw the object; commands like setStroke and stroke are thus illegal.
Related
I am trying to draw a Bezier path, an arc of a given angle, in response to a pan gesture. Here's what I have inside the function called by the pan gesture:
UIGraphicsBeginImageContext(self.frame.size);
UIBezierPath *path = [self createArcPath];
[[UIColor blackColor] setStroke];
[[UIColor redColor] setFill];
CGContextRef *ref = UIGraphicsGetCurrentContext();
path.lineWidth = 5;
[path fill];
[path stroke];
UIGraphicsEndImageContext();
And here is createArcPath:
- (UIBezierPath *)createArcPath
{
UIBezierPath *aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150)
radius:75
startAngle:0
endAngle:DEGREES_TO_RADIANS(135)
clockwise:YES];
return aPath;
}
I don't get an error, but I just don't get anything on my screen relating to the arc. What am I missing? This is in a method of a UIView subclass.
I also tried the following method in - (id)initWithFrame:
UIColor *color =[UIColor redColor];
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, width);
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGRect myOval = {100, 100, self.radius, self.radius};
CGContextAddEllipseInRect(context, myOval);
UIGraphicsEndImageContext();
I also don't see anything. What am I missing? Can these methods not be called from a UIView?
The UIGraphicsBeginImageContext/UIGraphicsEndImageContext calls create an off-screen context that you can draw into, then extract an image from. Since it's an off-screen context nothing shows on the screen.
What you probably want to do is create a custom subclass of UIView that overrides drawRect. In your code that responds to user gestures, change the data structure(s) that represent your drawing, then call setNeedsDisplay to trigger the system to ask your view to redraw itself by calling your drawRect method.
As an alternative you can set up your custom view to install a CAShapeLayer in the view, then change the path on the layer, then call setNeedsDisplay on the layer.
I have a custom view that will draw animations - just different lines, each line a different color. When user enters information, these lines appear originating at the button and creating lines to different UILabels.
I am following this tutorial techotopia.com core graphics iOS 7 tutorial
It says to make the UIView a custom class and put the drawing inside drawRect: - with your typical creating of context, adding lines, stroke, color, etc. OK fine, but how do I get multiple lines with different colors to be drawn simultaneously?
Do I need to create layers for each line? A new custom class and view for each line?
If I call CGPathCloseSubpathwill that allow me to create a new starting point?
How do I change the color for the new line, and do I need to create a new context for the new line?
Use UIBezierPath is easier than CGPath and CGContext.
-(void)drawRect:(CGRect)rect
{
UIBezierPath *line1 = [UIBezierPath bezierPath];
[line1 moveToPoint:CGPointMake(0, 0)];
[line1 addLineToPoint:CGPointMake(100, 0)];
[[UIColor redColor] set]; //Set color to red
[line1 stroke];
UIBezierPath *line2 = [UIBezierPath bezierPath];
[line2 moveToPoint:CGPointMake(0, 10)];
[line2 addLineToPoint:CGPointMake(100, 10)];
[[UIColor blueColor] set]; //Change color to blue
[line2 stroke];
}
I'm trying to draw something simple on screen when NSSetUncaughtExceptionHandler gets called but nothings happen.
Is there any other way to catch an exception and quickly draw something on screen?
NSSetUncaughtExceptionHandler(&exceptionHandler);
void exceptionHandler(NSException *exception)
{
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path moveToPoint:CGPointMake(10.0, 10.0)];
[path addLineToPoint:CGPointMake(10.0, 450.0)];
[path addLineToPoint:CGPointMake(310.0, 450.0)];
[path addLineToPoint:CGPointMake(310.0, 10.0)];
[path addLineToPoint:CGPointMake(10.0, 10.0)];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[APP_DELEGATE_WINDOW.rootViewController.view.layer addSublayer:shapeLayer];
[APP_DELEGATE_WINDOW makeKeyAndVisible];
}
I'm not sure that the NSSetUncaughtExceptionHandler is a good place to draw stuff on the screen.
Sets the top-level error-handling function where you can perform
last-minute logging before the program terminates.
Most crash reporters carefully log the trace and try not to "touch" anything besides.
If you really want to draw something (what?) you should maybe catch a particular exception first. Just not any uncaught exception.
I think Rivera is right, about NSSetUncaughtExceptionHandler. And maybe you need to write: [path fill];
P.S : I'm sorry that i write here, comments disabled, small reputation...
Like Rivera said, you won't be able to rescue the application at this stage, but if you really needed to draw something here, you could probably launch another process (which you would have to design) just to show this image.
I am trying to make a game where a ball is bouncing off a user drawn line. The code for drawing the line is included below and works fine but how would I remove the line once the ball makes contact with it or the player draws a new line?
path = [UIBezierPath bezierPath];
// Start Coords of Line
[path moveToPoint:CGPointMake(pos2x, pos2y)];
[path addLineToPoint:CGPointMake(pos1x, pos1y)];
// End Coords of Line
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path CGPath];
shapeLayer.strokeColor = [[UIColor whiteColor] CGColor];
shapeLayer.lineWidth = 3.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
[self.view.layer addSublayer:shapeLayer];
Thanks in advance!
When you say this:
[self.view.layer addSublayer:shapeLayer];
...also keep a reference to that shape layer. For example, you might have a property currentShapeLayer:
self.currentShapeLayer = shapeLayer;
Now that you have a reference, you can easily remove the layer:
[self.currentShapeLayer removeFromSuperlayer];
Programming iOS is all about keeping references to things you know you'll need later on. If there are more paths, meaning more shape layers, you will need a more complex, intelligent way of distinguishing which is which and which one you want to remove.
I have a weird issue with some basic drawing code here:
The code for this is just the following in a for-loop, I just want to draw some vertical lines into the view:
UIBezierPath* verticalLine = [UIBezierPath bezierPath];
[verticalLine moveToPoint:CGPointMake(currentXPosition, 0)];
[verticalLine addLineToPoint:CGPointMake(currentXPosition, self.frame.size.height)];
[verticalLine closePath];
verticalLine.lineWidth = 1;
[[UIColor blackColor] setStroke];
[verticalLine stroke];
I can't imagine a reason for it. Can you?
Thanks in advance,
Christian
EDIT: Drawing horizontal lines works perfectly well, they have normal width and don't fade out.