Beginner iphone question: drawing a rectangle. What am I doing wrong? - iphone

Trying to figure out what I'm doing wrong here. Have tried several things, but I never see that elusive rectangle on the screen. Right now, that's all I want to do -- just draw a single rectangle on the screen.
I'm getting an "invalid context" on everything but the CGContextSetRGBFillColor(). Getting the context after that seems kinda wrong to me, but I'm not at home looking at the examples I was using last night.
Have I messed up something else as well? I really would like to get at least this much done tonight...
- (id)initWithCoder:(NSCoder *)coder
{
CGRect myRect;
CGPoint myPoint;
CGSize mySize;
CGContextRef context;
if((self = [super initWithCoder:coder])) {
NSLog(#"1");
currentColor = [UIColor redColor];
myPoint.x = (CGFloat)100;
myPoint.y = (CGFloat)100;
mySize.width = (CGFloat)50;
mySize.height = (CGFloat)50;
NSLog(#"2");
// UIGraphicsPushContext (context);
NSLog(#"3");
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, currentColor.CGColor);
CGContextAddRect(context, myRect);
CGContextFillRect(context, myRect);
}
return self;
}
Thanks,
Sean.

Starting with a View-based template, create a project named Drawer. Add a UIView class to your project. Name it SquareView (.h and .m).
Double-click DrawerViewController.xib to open it in Interface Builder. Change the generic view there to SquareView in the Identity Inspector (command-4) using the Class popup menu. Save and go back to Xcode.
Put this code in the drawRect: method of your SquareView.m file to draw a large, crooked, empty yellow rectangle and a small, green, transparent square:
- (void)drawRect:(CGRect)rect;
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 0.0, 1.0); // yellow line
CGContextBeginPath(context);
CGContextMoveToPoint(context, 50.0, 50.0); //start point
CGContextAddLineToPoint(context, 250.0, 100.0);
CGContextAddLineToPoint(context, 250.0, 350.0);
CGContextAddLineToPoint(context, 50.0, 350.0); // end path
CGContextClosePath(context); // close path
CGContextSetLineWidth(context, 8.0); // this is set from now on until you explicitly change it
CGContextStrokePath(context); // do actual stroking
CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.5); // green color, half transparent
CGContextFillRect(context, CGRectMake(20.0, 250.0, 128.0, 128.0)); // a square at the bottom left-hand corner
}
You don't have to call this method for the drawing to happen. Your view controller will tell the view to draw itself at least once when the program launches and the NIB files are activated.

You are not supposed to put CG code in initWithCoder. That message should only be used for INITIALIZATION purpose.
Put your drawing code in:
- (void)drawRect:(CGRect)rect
If you are subclassing a UIView...

Related

drawing rectangle on button click in viewcontroller class in objective c IOS5

simply I am beginner in developing on ipad and I need to draw rectangle at point x,y with width and height when i clicked or touched button .
I searched on google but i didn't find anything working in button handler
Create rectangleButton in viewDidLoad method and write -(void)rectangleButtonSelected method in your ViewController.m. And also create class RectangleView of UIView.
-(void)rectangleButtonSelected{
RectangleView *temp = [[RectangleView alloc] initWithFrame:CGRectMake(0, 0, 60, 40)];
temp.center = CGPointMake(arc4random()%100, arc4random()%200);
NSLog(#"The Main center Point : %f %f",temp.center.x,temp.center.y);
[self.view addSubview:temp];
}
Implement - (void)drawRect:(CGRect)rect method in RectanglerView.m
- (void)drawRect:(CGRect)rect
{
// Drawing code
context =UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
// And draw with a blue fill color
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
CGContextAddRect(context, self.bounds);
CGContextStrokePath(context);
// Close the path
CGContextClosePath(context);
// Fill & stroke the path
CGContextDrawPath(context, kCGPathFillStroke);
}
I hope it will be helpful to you
You actually need to do this with state. There's only one place you're allowed to do drawing, and that's in drawRect:. So, when the user clicks the button, you need to set some instance variable, like _isShowingRectangle or something, then call setNeedsDisplay on your custom UIView where you're doing your drawing.
Then, in your custom view's drawRect:, you can check if that state variable is set, and draw (or not draw) the rectangle. The code for drawing depends on which graphics layer you're using, but it's probably going to be something like
CGContextRef ctxt = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(ctxt,[[UIColor blackColor] CGColor]);
CGContextSetLineWidth(ctxt,3.0);
CGContextStrokeRect(ctxt,CGRectMake(10,20,100,50));

iPhone Quartz Drawing Eraser

I am trying to make an iPhone application with erasing. I am running into 2 problems, if you have a solution for either one please answer this. I would like to erase part of an image.
1) I am currently just clearing the rect but it has a square edge. I would like it to be round, I have previously tried translating but this does not work. I also need it to translate/rotate as few times as possible to maintain the same performance.
2) In addition I wanted to know if there are any other ways of erasing. When erasing fast it is erasing ever 1/2 inch. Is there a way to stroke a path and clear the rect or something? Sorry if this is hard to understand.
CGRect circleRect = CGRectMake([touch CGPointValue].x, [touch CGPointValue].y, 25, 25);
CGContextClearRect(currentContext,circleRect);
This code should do what you're looking for:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.strokeWidth);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
CGContextStrokePath(context);
CGContextFlush(context);
The key points are
1) CGContextSetLineCap(context, kCGLineCapRound), which makes it round
2) CGContextSetBlendMode(context, kCGBlendModeClear) which clears the context.
I realize this is an older question but I thought I would expand on Eric Reids answer as I was trying to use his example outside of the drawRect method and had to modify it to get it to work with a context I created in a 'touchesMoved' method in a UIView subclass.
I call this method from 'touchesMoved' and pass it the CGPoint of the touch in the view I'm drawing in.
-(void) processEraseAtPoint:(CGPoint)point
{
// setup a context with the size of our canvas view (the canvas view is the UIView instance I'm drawing into)
UIGraphicsBeginImageContext(self.canvasView.bounds.size);
// get a reference to the context we just created
CGContextRef context = UIGraphicsGetCurrentContext();
// draw the image we want to edit into this context (this is the image containing the drawing I want to erase part of)
[self.canvasView.incrementalImage drawAtPoint:CGPointZero];
// set our context options
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.canvasView.settings.brushDiameter);
CGContextSetBlendMode(context, kCGBlendModeClear);
// make the color clear since we're erasing
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
// start our path in this context
CGContextBeginPath(context);
// set our first point
CGContextMoveToPoint(context, lastTouch.x, lastTouch.y);
// draw from our last point to this point
CGContextAddLineToPoint(context, point.x, point.y);
// stroke this path (in this case it's clear so it will erase what's there)
CGContextStrokePath(context);
// set our incrementalImage in the canvasView with the updated image from this context
// Note that in the canvasView 'drawRect' method I am calling
// '[self.incrementalImage drawInRect:rect]', so this new image will get drawn
// in my canvasView when I call 'setNeedsDisplay'
self.canvasView.incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
// cleanup our context
CGContextFlush(context);
UIGraphicsEndImageContext();
// set our last touch point for the next line segment
lastTouch = point;
// update our view
[self.canvasView setNeedsDisplay];
}

How to fill the shapes with color

I am new to Objective-C and iOS development. I have a view with some figures drawn by core drawing. Now I want to fill those shapes with color and I don't know the path or context of shape. Does Objective-C have any function like flood-fill or put-pixel so that by having only the stroke color I can fill any shape inside my view.
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 4.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {1.0, 0.0, 0.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextMoveToPoint(context, 50, 0);
CGContextAddLineToPoint(context, 0,320);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetRGBFillColor(context, 0, 255, 0, 1.0);
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGRect rectangle = CGRectMake(60,170,200,80);
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
This will make a circle and a square with some common region. I want a particular region to fill with color when a user taps that region.
So you are looking for flood fill in Objective C.
This is my implementation of Scan Line Flood Fill Algorithm.
Github : UIImageScanlineFloodfill
If you want to learn basic of flood fill:
Lode's Computer Graphics Tutorial Flood Fill
I hope this will help you.
Put your drawing code in the question and I can give you a specific answer.
Normally you just need to set a fill color using
[[UIColor redColor] setFill];
And any shapes you draw your core graphics will be filled with that color automatically.
Try this command:-
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
Core Graphics is closely tied to UIView and its drawRect: method and has a C interface. As you point out, you always draw in the current graphics context. I can think of 2 approaches: (1) When the user taps myView, set a property like myView.pointTapped, and in drawRect: find the shape to fill, set a fill color, and fill the closed path using GGGeometry methods.
There is an objective-C alternative: (2) Take a look at UIBezierPath. It's not as comprehensive as drawing in Core Graphics but it can be used in your ViewController implementation.

Shadow at the top of a Cell UITableCellView

I wondered if anyone knows how to get a shadaow effect like the one in things as per the screenshot. To me it looks like the shadow effect is created by having a shadow at the bottom of the cell above and the top of the cell below.
I can create the one from the cell above using the code below but can't figure out how to do it on the cell underneath as it doesn't get shown it's as if the cells are rendered in reverse order in terms of the z-index.
self.layer.shadowOffset = CGSizeMake(0, 2);
self.layer.shadowColor = [[UIColor blackColor] CGColor];
self.layer.shadowRadius = 2;
self.layer.shadowOpacity = 0.5;
CGFloat top = self.layer.bounds.origin.y;
CGFloat left = self.layer.bounds.origin.x;
CGFloat width = self.layer.bounds.size.width;
CGRect shadowFrame = CGRectMake(left, top, width, 44);
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
self.layer.shadowPath = shadowPath;
Any suggestions much appreciated.
Things http://www.purplesmash.com/images/Things.jpg
Just create hollow rectangle while drawing with CoreGraphics (align it exactly that hollow part cover your cell visible view) and set shadow for context - this will save performance for you.
UPDATE:
I've tried this inside my cell drawRect: method
// Creating path which will hold our hollow rectangle
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(-8.0f, -8.0f, 336.0f, 96.0f));
CGPathAddRect(path, NULL, CGRectMake(-5.0f, 0.0f, 330.0f, 80.0f));
// Saving current graphics context state
CGContextSaveGState(context);
// Configuring shadow
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 6.0f,
[[UIColor blackColor] CGColor]);
// Adding our path
CGContextAddPath(context, path);
// Configure hollow rectangle fill color
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
// Fill rectangle and keep hollow part transparent
CGContextEOFillPath(context);
// Restore graphics context
CGContextRestoreGState(context);
Of course additional improvement will be pre-calculate CGMutablePathRef path somewhere in initialization or in this method by condition if(path == NULL). Colors can be retained too. If this should be last row of your cell update, than maybe you don't event need to save context state.
You probably need to do this by drawing the shadows as part of the checked cell instead of setting the shadow properties on the surrounding cells.
I'd do it by adding one or two CAGradientLayers as children of the checked cell's contentView.layer.
I have edited this in light of the suggestion from moonlight. I put that code into a method addInnerTopShadow when a cell needs that I call the method. I have added another method addInnerBottomShadow which puts in the shadow at the bottom.
I call these methods in the drawRect method and when I want to change between the states I call the method:
[cell setNeedsDisplay];
This allows me to toggle the state of the cell without doing things like
[self.tableView reloadData];
As the methods suggest I have outer shadow methods that put a shadow on the first and last cells but that's another issue and has been answered many times. I now have my app working exactly how I want. So thanks to Rob and Moonlight.
-(void)addInnerBottomShadow
{
CGContextRef context = UIGraphicsGetCurrentContext();
// Creating path which will hold our hollow rectangle
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 44, 480, 80));
CGPathAddRect(path, NULL, CGRectMake(0, 54, 480, 96));
// Saving current graphics context state
CGContextSaveGState(context);
// Configuring shadow
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 6.0f, [[UIColor blackColor] CGColor]);
// Adding our path
CGContextAddPath(context, path);
// Configure hollow rectangle fill color
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
// Fill rectangle and keep hollow part transparent
CGContextEOFillPath(context);
CGContextClipToRect(context, self.bounds);
// Restore graphics context
CGContextRestoreGState(context);
}
-(void)addInnerTopShadow
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(-8.0f, -8.0f, 336.0f, 96.0f));
CGPathAddRect(path, NULL, CGRectMake(-5.0f, 0.0f, 330.0f, 80.0f));
// Saving current graphics context state
CGContextSaveGState(context);
// Configuring shadow
CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 0.0f), 7.0f, [[UIColor blackColor] CGColor]);
// Adding our path
CGContextAddPath(context, path);
// Configure hollow rectangle fill color
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
// Fill rectangle and keep hollow part transparent
CGContextEOFillPath(context);
CGContextClipToRect(context, self.bounds);
// Restore graphics context
CGContextRestoreGState(context);
}

Why is my CGContext clipped to bounds?

Should I be able to override drawInContext() and draw outside the bounds of my CALayer? Even though my layer has maskToBounds set to NO (the default) my drawInContext() is called with a clip set to the bounds of my layer and I am unable to draw outside of it.
My test layer does something like this:
-(void)drawInContext:(CGContextRef)context
{
[super drawInContext:context];
NSLog(#"mask to bounds=%d", self.masksToBounds); // NO
CGRect clip = CGContextGetClipBoundingBox(context);
NSLog(#"clip=%f,%f,%f,%f", clip.origin.x, clip.origin.y, clip.size.width, clip.size.height); // reports the bounds
CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);
CGContextBeginPath(context);
CGContextSetLineWidth(context, 5.0);
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 500, 0.0); // wider than my layer...
CGContextStrokePath(context);
}
and here is how I set it up:
- (void)viewDidLoad
{
[super viewDidLoad];
CALayer *layer = [[MyLayer alloc] init];
layer.needsDisplayOnBoundsChange=YES;
layer.frame = CGRectMake(50, 50, 200, 200);
[self.view.layer addSublayer:layer];
}
Is this just a limitation of core animation layers? (Do I need to draw in the layer above this layer?)
thanks.
There is no way for a layer's contents to overflow its bounds; however, you can add a sublayer that overflows by specifying a frame that stretches outside the bounds and setting the masksToBounds property to NO (the default).