Android: better way to apply custom fonts
Senin, 27 Februari 2012
0
komentar
In one application I had to apply customer's brand font for all controls of the user interface.
Sounds like a pretty common task, right? Yeah, I was thinking the same.
But then I was surprised that Android doesn't provide simply and elegant way to do this.
So, in this article I will show you what Android provides us by default. Then I will share with you my solution, which allows you to apply custom fonts in a more simple and elegant way.
Situation:
you have a custom font that should be applied for entire application screen.
Solution:
1) Android's default #1:
You can refer by id view controls, and apply typeface for each of them. In case of one view it looks not so scary:
Typeface customFont = Typeface.createFromAsset(this.getAssets(), "fonts/YourCustomFont.ttf");But in case of many TextView, Buttons, etc. view at your screen you will not love this approach, I can assure you! :D
TextView view = (TextView) findViewById(R.id.activity_main_header);
view.setTypeface(customFont);
2) Android's default #2:
You can create subclass for each TextView, Button, etc. and apply custom font in the constructor:
public class BrandTextView extends TextView {
public BrandTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public BrandTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BrandTextView(Context context) {
super(context);
}
public void setTypeface(Typeface tf, int style) {
if (style == Typeface.BOLD) {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/YourCustomFont_Bold.ttf"));
} else {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/YourCustomFont.ttf"));
}
}
}
Then just use that custom views instead of standard ones (i.e. BrandTextView instead of TextView).
<com.your.package.BrandTextViewAlso, you can even add your own attribute to set required font directly via XML. To make you will need to define your own declare-styleable attributes and parse attributes in the constructor.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View with custom font"/>
<com.your.package.BrandTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="View with custom font and bold typeface"/>
In order not to describe the basic things, I just point for a good article by Kevin Dion with an
example of custom attributes implementation:
http://kevindion.com/2011/01/custom-xml-attributes-for-android-widgets/
In general solution #2 not so bad and has it's own advantages (for example, to switch between regular, bold, etc. fonts based on specified "typeface" attribute value). But in my opinion it's still too heavy and requires a lot of boilerplate-code for such a simple task as applying custom font.
3) My solution:
the ideal solution would be to define custom theme and apply it to entire application or Activity.
But unfortunately Android's android:typeface attribute can only use inbuilt fonts, but not the custom fonts (e.g. from the assets). That is why we can't get away from the loading and applying fonts at runtime in Java code.
So I decided to create a helper class to make it as simple, as possible.
The usage of it looks like:
FontHelper.applyFont(context, findViewById(R.id.activity_root), "fonts/YourCustomFont.ttf");And this one string will apply custom font for all TextView based controls (TextView, Button, RadioButton, ToggleButton, etc.) at your screen regardless of their layout hierarchy! ;-)
Standard (left) and Custom (right) fonts usage. |
public static void applyFont(final Context context, final View root, final String fontName) {As you can see there is nothing more then looking for TextView based views at all levels of layout hierarchy.
try {
if (root instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) root;
for (int i = 0; i < viewGroup.getChildCount(); i++)
applyFont(context, viewGroup.getChildAt(i), fontName);
} else if (root instanceof TextView)
((TextView) root).setTypeface(Typeface.createFromAsset(context.getAssets(), fontName));
} catch (Exception e) {
Log.e(TAG, String.format("Error occured when trying to apply %s font for %s view", fontName, root));
e.printStackTrace();
}
}
You can download sample project with usage of FontHelper here.
Baca Selengkapnya ....