7

I can't get to achieve a smooth very slow text animation in a Canvas because Canvas.drawText doesn't want to draw "between pixels". For example, given 4 consecutive frames where I draw a text with an Y offset of 0, 0.5, 1, 1.5, the canvas will actually draw it at offsets 0, 0, 1, 1, respectively, which causes the animation to be "jerky". There's a flag called Paint.SUBPIXEL_TEXT_FLAG that's supposed to keep the float precision.

I found a related thread in which Romain Guy said that this flag is currently not supported in Android: Meaning of some Paint constants in Android.

My question is: is there any existing workaround ?

Note: Drawing the text in another bitmap once, then draw this bitmap with float offsets instead of drawing the text doesn't seem to work either.

Community
  • 1
  • 1
Joan
  • 143
  • 2
  • 9

1 Answers1

3

You could simulate this effect by drawing two texts side-by-side with alpha balancing (between 127 and 255) between the two elements.

Let's assume your text is moving from up to bottom, and the current vertical position is 10.28. You just have to draw one text at position 10 with an alpha near of 127 and the other text at position 11 with an alpha near of 255.

Here is a little (ugly :D) example :

private void doDraw(Canvas canvas) {
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.BLACK);
    paint.setTextSize(20);
    canvas.drawRect(0, 0, getWidth(), getHeight(), paint);

    mY += 0.05f;
    paint.setColor(Color.RED);

    if (Math.floor(mY) == mY) {
        canvas.drawText("test", mX, mY, paint);
    } else {
        float mY1 = (float) Math.floor(mY);
        float mY2 = mY1 + 1;
        float delta = mY - mY1;

        paint.setAlpha((int) ((1 - delta) * 127) + 127);
        canvas.drawText("test", mX, mY1, paint);

        paint.setAlpha((int) ((delta) * 127) + 127);
        canvas.drawText("test", mX, mY2, paint);
    }
}
DayS
  • 1,561
  • 11
  • 15
  • Thanks for you answer, that's quite a nice solution, and it's indeed close to what I expected `Paint.SUBPIXEL_TEXT_FLAG` to do. It has some down sides though. Text is drawn twice, and with antialiasing, which causes an unwanted blur effect along with a _fake bold_ text, sort of. I'll try to play a little bit with it but from what I can see, it's still not smooth. Note that i'm using a 42" screen with a 1280x720 resolution: a pixel is quite big and the animation is _really far from being smooth_. – Joan Sep 14 '12 at 09:53
  • Indeed, the text will look bold but you have to keep in mind that because you're text can't be drawn between two pixels, so you have to deel with that by drawing it on two pixels. I don't think there is another solution but, of course, the algorithm can be improved. – DayS Sep 14 '12 at 09:59
  • I'll keep you posted, if I can't find anything better I'll resign myself and validate your answer. :) For now I keep hope there's a magic trick somewhere. – Joan Sep 14 '12 at 10:16