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 ?
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.
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.
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.
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.
Related
I'm trying my best to follow the material design guidelines when it comes to fonts as I can, but I'm struggling to fix an issue I'm having without using dimens dependant on density. My issue is;
I'm using styles for my fonts so an example of this;
<style name="Text.MyApp.Heading3" parent="TextAppearance.MaterialComponents.Headline3">
<item name="android:fontFamily">?attr/RegularFont</item>
<item name="fontFamily">?attr/RegularFont</item>
<item name="android:textSize">?attr/TextSizeHeadingThree</item>
</style>
And applying this as the style of the text, my font size comes from the material guidelines so for Heading 4 I have
<dimen name="text_size_heading_three">48sp</dimen>
My problem is, I've got a view where there's two numbers using Heading3 in a row on the screen, This may look like +£100.00 | -£200.00, these are constrained to a separator view in the middle.
Where my issue lies is on a Pixel 4 XL (xx-hdpi) this looks fine, but bringing this down onto a Nexus S (hdpi) the text squashes together, overlaps the separator in the centre and comes off the end of the screen slightly.
It was to my understanding of the use of SP is that it would scale this text size which doesn't appear to be happening, a worry also arises that SP takes from the users text size preferences so increasing the text size of the device will likely also break this.
Just short of changing the font size for hdpi to a smaller text size for this text view, is there a way I can make this style scale with the screen?
sp actually scales in regard to the screen pixel density and the selected font size of the system.
The issue you are facing is related to the screen's actual width instead.
To achieve what you want, you can try either of the following two:
Have different sp values for your dimen for each screen width. You can do this by creating additional resource files that would contain your dimen values and will be screen width dependant. You can read more about this here:
https://developer.android.com/training/multiscreen/screensizes#TaskUseSWQuali
Use an autosizing TextView. You can find more information here:
https://developer.android.com/guide/topics/ui/look-and-feel/autosizing-textview
sp units are literally about the user's choice of text size:
Scale-independent Pixels - This is like the dp unit, but it is also scaled by the user's font size preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted for both the screen density and the user's preference.
Basically users can choose the general size of text on their device, and that multiplies dp values by a specific factor (Normal is * 1.0, I think Huge is * 2.0) and that's what the sp value is. When you specify sizes in sp, you're allowing the system to scale that text up so it's readable for everyone.
So you need to be mindful of that when designing - it's always worth having an emulator with a small screen (limited space) and the text size set to the largest setting, just to make sure everything still fits in those extreme cases.
You have four options I think:
reduce your font's sp size in the layout, so it always fits
make different layouts for different configs, and tweak that (more work for you)
use autosizing TextViews like #kandrit mentions - set the space you want to fill, and it will scale the text size to fit it (this sounds like what you were expecting, and you can tweak things like having a fixed set of possible sizes)
don't use sp, use dp instead (won't scale according to the user's preference - but above a certain size, it doesn't need to because it will be readable)
You'll get a warning about the last one, but in my opinion it's completely fine and the right thing to do in some cases. Think about an app with a clock in the middle of the screen - it's a fixed size, designed and laid out a certain way, and it's large enough to be easily read. It's meant to look a specific way, take up a specific area of the screen, and there's no need for it to change size - so it makes sense to define it in dp like any other visual element. Maybe that works for what you're doing!
Problem is not with your text size, it is with your layout design
I also had the similar problem I solved it by giving a margin to views which was placed inside constraint layout so in a case of large screen it will use constraints and ignore the value of margin and in case of small screen it use the value of margin to keep views separate
If you are using a Linear Layout then set layout_weight to 1 and give margins to views then it will work same as with constraint layout
I am making an Android application for multiple screen device.
I want to know what should be the text size scale ratio for different density device?
example : if my text size is 28sp on mdpi device then what should be on hdpi device?
I made values-ldpi, values-mdpi, values-hdpi etc. and define text size in dimens of each respective values folder, but it did not look similar on all device.
You dont need to know the ratios, and you shouldnt directly use them since the amount of densities keep changin.
If you use it in the resources, using the sp unit will do it work fine in every density, without diferent value folders.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="type1">28sp</dimen>
</resources>
If you do it from code, probably it will look diferent depending on howyou asign the values. You have to send the correct values to the setTextSizeFunction, for example:
setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimensionPixelSize(R.dimen.type1));
//he documentation method that COMPLEX_UNIT_PX returns a Resource dimension value multiplied by the appropriate metric.
or with hardcoded numbers:
setTextSize(TypedValue.COMPLEX_UNIT_SP, 9);
Use below formula for declaration in dimens.xml
base mdpi= 1X
HDPI= 1.5X
XHDPI=2.0X
XXHDP=2.75X
above formula for relation b/W all Resolution
The app design that I'm implementing requires icon sizes to be a function of font size. The height of the icon should roughly match the height of the font.
It appears to be possible to specify any view size in sp.
Google has decreed that layout sizes should not be specified in sp but is there anything to stop me specifying an ImageView size in sp? It appears that nobody else is doing this and I'm worried about falling into unforeseen traps.
You could use the align options to size the icon
android:layout_alignTop="#+id/your_font_view"
android:layout_alignBottom="#+id/your_font_view"
and set android:scaleType to the appropriate value.
It would probably be best to be in a RelativeLayout as well
From android dev site
"A dp is a density-independent pixel that corresponds to the physical size of a pixel at 160 dpi. An sp is the same base unit, but is scaled by the user's preferred text size (it’s a scale-independent pixel), so you should use this measurement unit when defining text size (but never for layout sizes)."
Yes, you can safely specify the ImageView size in sp. This is not recommended for layouts because they typically scale to fit their content and specifying their size in sp would a) be unnecessary and b) probably look bad.
In my Layout there are 3 buttons which are horizontally equally divided using weight.
Now I am setting the custom font Roboto on the button.
The problem is how to calculate the size on the font based on resolution and dpi, so that it looks proper on all sizes of android devices.
Option #1: Specify the font size in sp, which takes density and user-requested font scaling into account.
Option #2: Specify the font size in dp, which takes density into account, but ignores the user's requested font scaling.
Option #3: Use the logic from AutoScaleTextView to create an AutoScaleButton that changes its font size to fit the available space (even though this means that each button would have a different font size)
Option #4: Extend Option #3 by having a collection of AutoScaleButton instances negotiate a common font size among them, picking the smallest one that fits all three buttons, so that the font size is the same (even though the text might not fill two of the three buttons, depending on the caption length in characters, etc.).
take dimension variable for all dpi
<dimen name="detail_photo_size">80sp</dimen>
in values-hdpi,values-ldpi,values-mdpi and then use like:
txtballoon_item_title
.setTextSize(getResources().getDimension(R.dimen.detail_photo_size));
I am looking for a way to convert from UIFont's size to Android TextView's textSize attribute, for example:
[UIFont fontWithName:#"HelveticaNeue" size:14];
The iOS Dev Doc specifies the unit of the UIFont size attribute as point, however on Android's Text View uses px, dp, sp, in, or mm.
On Android what should I write for:
<TextView android:textSize="?" />
Thanks!
If you check the Android Developers site it will give you the appropriate format and sizing units for TextView. You have: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size), in (inches), or mm (millimeters).
A font in defined in points is actually defined in physical inches. That conversion is the most straightforward, and probably the poorest way to do this, but you can convert to inches by simply multiplying the point size by the ratio of points to a physical inch: 1/72
In order to convert the point size to pixels you can make use of a calculation available at this site: https://web.archive.org/web/20120415064052/http://www.emdpi.com/screendpi.html
Some of the information there is Windows specific, but the basic method should work for Android as well, provided that you can identify your screen dpi. This method will give you the appropriate value in pixels (px), which is valid for the TextView font size.
Note, TextView recomends the use of scaled pixels (sp) for use with TextView, so you may need to do some additional work to scale your font to your screen size programmatically.