Search code examples
iphoneobjective-cquartz-2d

Simple animation via delayed drawing


I'm trying to implement some very simple line drawing animation for my iPhone app. I would like to draw a rectangle on my view after a delay. I'm using performSelector to run my drawing method.

-(void) drawRowAndColumn: (id) rowAndColumn
{
    int rc = [rowAndColumn intValue];
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 2.0);
    CGContextSetStrokeColorWithColor(context, currentColor.CGColor);
    CGRect rect = CGRectMake(rc * 100, 100, 100, 100);
    CGContextAddRect(context, rect);
    CGContextDrawPath(context, kCGPathFillStroke);

}

Which is then invoked via:

int col = 10;
[self performSelector:@selector(drawRowAndColumn:) 
           withObject:[NSNumber numberWithInt:col]
           afterDelay:0.2];

But it seems that when the drawRowAndColumn: message is actually sent, it no longer has access to a valid CGContextRef, as I get errors such as:

<Error>: CGContextAddRect: invalid context

If I replace the performSelector with a direct call to drawRowAndColumn, it works fine. So my first idea was to also pass in the CGContextRef via the performSelector, but I can't seem to figure out how to pass multiple arguments at the same time (that's another good question.)

What's wrong with above code?


Solution

  • You can't just draw at any time like that. You need to implement the drawRect: method of UIView and put your drawing code in there. To get drawRect: to fire you need to let Cocoa know that the view needs to be drawn. For that you can call setNeedsDisplay, or setNeedsDisplayInRect:.

    Directly translating your attempt this way you'd call setNeedsDisplay using performSelector:withObject:afterDelay - but that's probably not a good way to do animation.

    It depends what you're really trying to do - but you could consider, for example, putting your drawing code in drawRect as I suggested, but start the view hidden. You could then call setHidden:NO using performSelector to make it appear after a delay - or you could smoothly animate it in by starting not hidden, but with an alpha of 0, then change alpha to 1 within a UIView animation block (there's lots about this in the docs).