I'm trying to find a way to draw lines on a view without redrawing all the context.
Here is my drawing methods :
-(void)drawInContext:(CGContextRef)context {
for (int i = 0; i < self.drawings.count; ++i) {
Drawing* drawing = [self.drawings objectAtIndex:i];
CGContextSetStrokeColorWithColor(context, drawing.colorTrait.CGColor);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, [[drawing.points objectAtIndex:0] CGPointValue].x * self.zoomScale, [[drawing.points objectAtIndex:] CGPointValue].y * self.zoomScale);
for (int i = 1; i < drawing.points.count; i++) {
CGContextAddLineToPoint(context, [[drawing.points objectAtIndex:i] CGPointValue].x * self.zoomScale, [[drawing.points objectAtIndex:i] CGPointValue].y * self.zoomScale);
}
CGContextStrokePath(context);
}
}
-(void)drawRect:(CGRect)rect {
if (isRedrawing) {
[self drawInContext:UIGraphicsGetCurrentContext()];
isRedrawing = NO;
}
[[UIColor redColor] set];
[currentPath stroke];
}
But when I call setNeedsDisplay in my touches methods, the view is entirely cleared. Is there a way to make my method work ?
For better or for worse I use layers:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
if (first) {
// Wait for the first call to get a valid context
first = NO;
// Then create a CGContextRef (offlineContext_1) and matching CGLayer (layer_1)
layer_1 = CGLayerCreateWithContext (context,self.bounds.size, NULL);
offlineContext_1 = CGLayerGetContext (layer_1);
// If you have any pending graphics to draw, draw them now on offlineContext_1
}
// Normally graphics calls are made here, but the use of an "offline" context means the graphics calls can be made any time.
CGContextSaveGState(context);
// Write whatever is in offlineContext_1 to the UIView's context
CGContextDrawLayerAtPoint (context, CGPointZero, layer_1);
CGContextRestoreGState(context);
}
The idea is that though the UIView's context is always cleared, the offline context associated with the Layer is not. You can keep accumulating graphical actions and not have them cleared by drawRect.
EDIT: So you've pointed out one difference between your problem and the one I solved. I didn't need to draw anything until after the first display whereas you want to draw something before the first display. From what I remember, you can create a layer at any time at any size and resolution. I found it was easiest to wait for a valid context (with the right settings for the current device) to be passed to me and then create a new context/layer based on that context. See the inside of the "if (first)" block.
You can do the same thing, but you'll also have to cache the lines etc that you get from the server until such time as the first drawRect: is called. You can then create the offline context with the given context, draw the lines etc. that you got from the server to the offline context and then draw the layer as shown below. So the only thing you'd add to the method is a call inside the "if (first)" loop to draw pending server-sources graphics before continuing (see added comment in source).