Alexander Farber
Alexander Farber

Reputation: 22988

Defining text size for Canvas.drawText() in res/values/dimens.xml

In a Scrabble-like word game app I am trying to draw black letters and values on yellow tiles.

While this works at Android emulators under Windows and Mac:

Mac screenshot

Windows screenshot

This doesn't work (the text size is too big) on real devices like Moto G, Nexus 1 and 4:

Real devices

I define the text sizes of 60sp and 20sp (I've tried dp too) in res/values/dimens.xml:

<resources>
    <dimen name="big_tile_letter">60sp</dimen>
    <dimen name="big_tile_value">20sp</dimen>
</resources>

And then use them in my BigTile.java class:

    int letterSize = context.getResources().getDimensionPixelSize(R.dimen.big_tile_letter);
    mLetterPaint = new Paint();
    mLetterPaint.setTextSize(letterSize);
    mLetterPaint.setAntiAlias(true);

    Rect letterBounds = new Rect();  
    mLetterPaint.getTextBounds(letter, 0, letter.length(), letterBounds);
    mLetterX = 0.45f * (width - letterBounds.width());
    mLetterY = 0.45f * (height + letterBounds.height());

    canvas.drawText(letter, mLetterX, mLetterY, mLetterPaint);

What am I doing wrong?

Upvotes: 9

Views: 2689

Answers (4)

Karsten
Karsten

Reputation: 310

Using dp for the text sizes is definitely the way to go here, unless you wanted to manually compensate for the user's font size setting by scaling your images as well.

Your problem is that your big_tile image has inconsistent sizes in the mdpi (128x128) and xxhdpi (256x256) variants: xxhdpi should be 3 times the resolution of mdpi, but your image is only 2x the size, making it effectively ~85dp instead of 128dp.

I'm pretty sure I've seen Android Lint warn about this sort of stuff, try running it on your project.

Upvotes: 1

yoah
yoah

Reputation: 7230

The problem is that setTextSize gets the size value in SP, not in pixels. In your case getDimensionPixelSize converts sp to pixels, and then setTextSize treats the pixels as sp, and scales up again.

public void setTextSize(float size)

Set the default text size to the given value, interpreted as "scaled pixel" units. This size is adjusted based on the current density and user font size preference.

To fix this, you can call

setTextSize (TypedValue.COMPLEX_UNIT_PX, letterSize)

Upvotes: 2

Flo
Flo

Reputation: 1499

One thing that comes to mind is that you are using sp values, which depend on the user setting in Settings / Display / Font Size. Can you check whether the setting is like Large or so - this would apply an additional scaling on your font size. Also, I believe for 2.x devices the default setting is different than for 4.x devices (not sure though).

You could try use dp values and see if that makes any difference.

Upvotes: 2

TacB0sS
TacB0sS

Reputation: 10266

If what you want to is to convert a value from the R.dimen.something into pixels so:

float textSize = getResources().getDimensionPixelSize(R.dimen.something);

If what you want is to supply a manual value or something like that:

float maxTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, maxTextSize, getResources().getDisplayMetrics());

Upvotes: 7

Related Questions