Alex Ionescu
Alex Ionescu

Reputation: 423

Best practices for animating shapes under Android Canvas

I have a custom view that draws a few circles and about 10 arches that are constantly updating (rotation and size change). I am trying to animate this whole process, but I couldn't find any good practices for doing so under Canvas (I know the basics - use dp instead of px and so on), but I don't know hot to properly do the animation part.

Right now I'm iterating trough all of my objects, perform some calculations to determine the future position and draw them, but it looks choppy. Here is what I'm currently doing:

@Override
protected void onDraw(Canvas canvas) {
    for(Arch arch : arches) {
        arch.update();
        canvas.drawArc(arch.getRect(), -arch.getCurrentRotation(), arch.getSweepAngle(), true, paint);
    }

    //logo.draw(canvas);

    canvas.drawCircle(width / 2, height / 2, circle_size, paint_opaque);

    logo.draw(canvas);

    int textX = (int) (width / 2);
    int textY = (int) ((height / 2) - ((paint_text.descent() + paint_text.ascent()) / 2));

    canvas.drawText(text, textX, textY, paint_text);
    invalidate();
}

Upvotes: 3

Views: 956

Answers (1)

Bartek Lipinski
Bartek Lipinski

Reputation: 31438

There are few things wrong with your code.

  1. You shouldn't be performing any heavy operations in the onDraw of your custom Views. That's one, really important principle of developing for android! Ideally inside your onDraw method you should ONLY draw. Sometimes you need to calculate something based on Canvas, but you should limit these sort of actions to the minimum. Everything you can preallocate and calculate somewhere else (not in onDraw), you should extract from your onDraw. In your case arch.update() (which I assume calculates the next "frame" of the animation) and calculation of your textX and textY should be moved somewhere else.

  2. invalidate() basically means that you request for a redraw of your View. When a View is being redrawn, its onDraw will be called. That's why you really shouldn't be calling invalidate() in your onDraw! If every single onDraw requests for another onDraw, it causes a sort of an infinite loop to happen.

  3. If you're trying to achieve a frame animation, you should be calculating all frame-related parameters in a separate thread that would wait some interval between updates, and would call invalidate() after every single one of them.

Upvotes: 3

Related Questions