Android: Canvas.drawText() text size on different screen resolutions
Solution 1
The easiest way is to define your font sizes in your resources with the units of scale-independent pixels (sp
) -- this unit is like density independent pixels (dp
or dip
) in that it takes into account the screen density but it also takes into account the font-size setting of the user.
To add a new dimension create a dimens.xml
file in your res/values
folder and enter the following code to add a new dimension with the name myFontSize
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="myFontSize">20sp</dimen>
</resources>
You can then get the text size in your application using
int scaledSize = getResources().getDimensionPixelSize(R.dimen.myFontSize);
The resulting size will be correctly scaled to take into account the current screen density and font-size setting.
For more information see the Android Developers page on More Resources.
Solution 2
You can do it yourself using a simple math operation:
You need to calculate a relation that draws your text just the same size for any canvas size, so use the actual canvas size, like this:
double relation = Math.sqrt(canvas.getWidth() * canvas.getHeight());
But that number is just too big, so divide it by one that suits your needs, lets say 250:
relation = relation / 250;
Now you can set your text size like this:
paint.setTextSize((float) (myFontSize * relation));
You don't have to necessary divide relation by any number but in that case you will have to use very small font sizes for the variable myFontSize
. For me 250 works just fine to use regular font sizes that will adjust to any screen size, since you are already taking in count the pixels dimension from your canvas.
Solution 3
The easiest way is to define your font size in your resources directory with the units of scale-independent pixel (sp)
or the density-independent pixel (dp)
. Then get the text size using
int scaledSize = getResources().getDimensionPixelSize(R.dimen.font_size);
mTextView.setTextSize(scaledSize);
This will scale the text-size appropriately according to the current screen density/resolution and the user's font-size setting.
How to define font size in resource directory?
Create a file named dimens.xml
in the folder res->values
. Then copy the following code.
<resources>
<dimen name="font_size">25sp</dimen> // sp or dp accordingly
</resources>
The name
attribute of the tag <dimen>
will be used as resource ID.
Solution 4
When calling Canvas.drawText()
the text size is first determined by the passed in Paint
object, which can be set via Paint.setTextSize()
. The text size is automatically scaled by Canvas
based on the canvas density, which can be found using Canvas.getDensity()
.
When setting the text size on a paint object that will be drawn on Canvas, work with a unit value of dp
or sp
and let Canvas handle the scaling for you.
twig
Updated on March 11, 2020Comments
-
twig over 4 years
For my Android game I have some calls to
Canvas.drawText()
.For testing, I use the standard font size which seems to be working fine.
However, when I bump up the resolution to a higher density, the larger images are automatically loaded but the text is now incredibly small.
Is there an easy way to calculate what size the text should be drawn at or am I bound to do this manually?
edit: What was the point of editing my post @Suragch ?
-
twig over 13 yearsInteresting method, I'll be sure to try it when I get a chance.
-
twig over 13 yearsThanks Joseph, that worked like a charm. I must admit that I was applying it on the wrong Paint object and realised much later. Marcin's solution would of worked fine also.
-
Trung about 13 years
-
HGPB almost 12 yearsJoseph, are you saying ADD R.dimen.font_size and set it to 20sp for example. Then by call this the 20sp will be scaled automagically to whatever screen? Or do we have to add a number of font_size dimensions for each screen res?
-
ElYeante about 10 yearsI can't understand why this is not the default behavior.
-
CrandellWS over 8 yearsa similar approach without a resource file stackoverflow.com/a/3062023/1815624
-
Neph about 4 yearsI tested
myPaint.setTextSize(80)
(called beforecanvas.drawText
) with different emulators (Nexus One=480x800 up to Nexus XL=1440x2560) and the text was always the same size (e.g. always 1 "real life" cm on the screen). Not sure if this was changed at one point (I'm using Java 8/API 27) but there seems to be no need to compute the size because the canvas automatically scales it accordingly. -
Neph about 4 yearsUpdate: I now tested your suggestion with different emulators and it doesn't give the desired result (anymore?): E.g. font size 22 (with your code) looks fine on a Pixel XL (1440x2560, 560dpi) but on a Nexus One (480x800, hdpi=240dpi) it's tiny/not readable anymore.