2

I want to make my app to draw a circle centered at the touch coordinates.

Here's the code I have right now, it is messed up for sure, I haven't had any practice with drawing things and working with context. What am I missing here? Thanks in advance.

View controller is a subclass of UIViewController

@implementation ViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
    // Custom initialization
}
return self;
}

- (void)viewDidLoad
{
[super viewDidLoad];
}

- (void)viewDidUnload
{
[super viewDidUnload];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *theTouch = [touches anyObject];

[self doSomething];

//[self.view setNeedsDisplay];

}

- (void) drawCircleAtPoint:(CGPoint)point withRadius:(CGFloat)radius inContext:(CGContextRef)context{
UIGraphicsPushContext(context);
CGContextBeginPath(context);
CGContextAddArc(context, point.x, point.y, radius, 0, 2*M_PI, YES);
CGContextFillPath(context);
UIGraphicsPopContext();
}

- (void)drawRect:(CGRect)rect
{
CGPoint point;
CGContextRef context = UIGraphicsGetCurrentContext();
point.x = self.view.bounds.origin.x + self.view.bounds.size.width/2;
point.y = self.view.bounds.origin.y + self.view.bounds.size.height/2;
CGContextSetLineWidth(context, 5.0);
[[UIColor whiteColor] setFill];
[self drawCircleAtPoint:point withRadius:50 inContext:context];

}

@end

Here I wanted it to draw the circle at least on the center of the screen, but I can't do even this.

nemesis
  • 1,349
  • 1
  • 15
  • 30
  • 1
    have you verified that you are running your drawRect and drawCircle code? Why are you doing a white fill? what is your background color? – heckman May 24 '12 at 18:53

2 Answers2

4

drawRect is a method of UIView class. It won't be available in a ViewController and hence wont be called.

ideally what you should do is to place the drawRect and drawCircleAtPoint in a UIView subclass. Also add the touches Methods in that view class. You can call it, DrawCircleView or something.

Now create an object of this custom view and add it as a subview to your viewcontroller's view in viewDidLoad.

call setNeedsDisplay in the touches method and store the point of touvh in a CGPoint instance variable and access it in drawRect.

UPDATE

You may want to save the previously drawn circles.

There are many possibilities, choose whatever suits you the best , I have not given you detailed explanation on each but enough info to get you going.

  • If you want circles to be editable then you will have to continue adding the circle info regarding the center and radius as one object in an NSMutableArray. and in the beginning of your drawRect you will have to redraw all of them in a loop.

    Infact I would suggest you to use CGPath and keep adding circles to that path and add the path to cgcontext in drawRect keep CGPath as an instance var so that it retains previous information from last drawRect call. But again If you want to be able to have circles drawn with different color then they will have to be in different CGPaths then you can add these CGPath with color info in an object into an mutable Array again.

OR

  • saving and redrawing all those circles will hinder the performance if the array keeps growing. If you dont want undo capabilities or you dont want to edit previous circles. Then you can save whatever is drawn in the end of drawRect as imageData and then keep it as an instance var and redraw it every-time drawRect is called and then draw a circle on top of it and save image again into the same instance.

For example: at the end of drawRect you can save image of your screen into instance-variable _savedImage.

  _savedImage = UIGraphicsGetImageFromCurrentImageContext(); 

and while redrawing in the beginning of drawRect,if _savedImage is not nil then,

 [_savedImage drawInRect:rect];

then you can draw the circle around the point you tapped on. Also If you want then you can save the drawing into actual image file anytime you want with:

 NSData *imageData = UIImagePNGRepresentation(_savedImage);
[imageData writeToFile:@"imageName.png"];

OR

  • If you want you can explore CGContextSaveGState() and CGContextRestoreGState() They are used to push and pop context to stack respectively. So you can get last context and redraw it and in between restoring and saving you can draw your circle. Checkout this stackOverflow post on the same: Saving and restoring CGContext
Community
  • 1
  • 1
Amogh Talpallikar
  • 12,084
  • 13
  • 79
  • 135
  • Thanks! But everytime when I'll tap, a new circle will be drawn and the old one will be removed? Is there something I can do to draw new circles on touch, and keep the old ones? – nemesis May 25 '12 at 10:17
  • Actually I've made it to actually work! The thing is - when you click, it generates a random radius for the circle, and this is kinda cool, coz I've made a class called Circle and I store it's coordinates and radius in order to redraw them fom an array when I add a new circle. And what I want to do now, is to make so that the circles wont overlap each other. I mean - if there are 5 big circles in an arc and you try to put a new one in between them it will generate a certain radius. Another way to put this question : is there any way I can determine if 2 certain CGRect's are intersecting? – nemesis May 25 '12 at 12:15
  • use Use bool CGRectIntersectsRect (CGRect rect1,CGRect rect2); – Amogh Talpallikar May 25 '12 at 12:46
  • there are many sucg functions to check point contained in a rect etc – Amogh Talpallikar May 25 '12 at 12:46
  • Hey could you check my new post? http://stackoverflow.com/questions/10757166/a-new-rectangle-does-not-intersect-old-ones Thanks – nemesis May 25 '12 at 15:58
3

The method call of drawRect occurs in a UIView, not in the UIViewController - the UIViewController manages a view, and handles delegation and other related items itself. Drawing occurs in the viewController's view property.

In your case, you will want to do the following:

  1. Subclass UIView with your own view, with the drawRect and drawCircle methods implemented there
  2. Replace the default UIView in the XIB with your own class (IB -> Identity Inspector -> Custom Class)
  3. Hook up events to detect finger touches and then force it to refresh using [view setNeedsDisplay]

Note: subclassing and overriding a UIImageView's drawRect does nothing - it is handled specially:

The UIImageView class is optimized to draw its images to the display. UIImageView will not call drawRect: a subclass. If your subclass needs custom drawing code, it is recommended you use UIView as the base class.

CrimsonDiego
  • 3,616
  • 1
  • 23
  • 26