Extending Components and AppTheme with Material Design
Recently I have been dealing with custom font in the default components of Android. However I need to use different fonts in English and one font in Chinese. As we know integrating custom fonts with the default components shipped out by Android is a bit tricky specially if you have to cater earlier version of the platform. To fix this problem, i need to extend the components first and this StackOverflow post helped with setting up the classes.
Another piece of the puzzle is with making it use the widget tinting that comes with appcompat v21. We need this because without it we need to generate a lot of files (drawable, styles, etc) and maintaining them is not fun. For this, we refer to the appcompat v21 material design for pre lollipop where we just need to put colorAccent, colorControlNormal, colorControlActivated, colorControlHighlight & colorSwitchThumbNormal. But then, our problem is that if we extend RadioButton, EditText and others, the tinting is not applied. Initially I extended the style of the RadioButton to android:Widget.CompoundButton but nothing happens, then I make sure that if I just use RadioButton and set the color* that it would work and it did. After few tries, I went back to StackOverflow and found this in where it tells use to extends the internal class.
So I made an experiment and here is the gist
First, we create a FontUtils so that we could reuse it with different components
The full class is here, basically here we create a helper class that would set the typeface based on the fontName that is passed from the xml. We create the typeface from the files we have under assets/ using the Typeface.createFromAsset(context.getAssets(), resources.getString(R.string.font_thin)); where the getString() will load the path of the string based on the locale we have. For example we passed in 0 (FONT_REGULAR) we would then load fonts/Roboto-Regular.ttf for English and fonts/NotoSansCJKtc-Bold.oft for Chinese.
For the custom class we have RadioButton as example but it could easily be done with EditText, CheckBox, Spinner using the prefix Tint.
Here we just pass the mFontName to our FontUtils helper, we got that from the xml on our layout.
To create our RadioButtonCustomFont on our layout we must do something like this
Here we create a namespace for font (the same as the name in our assets.xml) then we pass in font:name the value/s from the assets.xml.
Finally we need to apply the tinting that comes with appcompat, for that take a look at the our themes.xml and its explanation is the same as Appcompat for pre-lollipop theming part
Hope this helps :)
Another piece of the puzzle is with making it use the widget tinting that comes with appcompat v21. We need this because without it we need to generate a lot of files (drawable, styles, etc) and maintaining them is not fun. For this, we refer to the appcompat v21 material design for pre lollipop where we just need to put colorAccent, colorControlNormal, colorControlActivated, colorControlHighlight & colorSwitchThumbNormal. But then, our problem is that if we extend RadioButton, EditText and others, the tinting is not applied. Initially I extended the style of the RadioButton to android:Widget.CompoundButton but nothing happens, then I make sure that if I just use RadioButton and set the color* that it would work and it did. After few tries, I went back to StackOverflow and found this in where it tells use to extends the internal class.
So I made an experiment and here is the gist
First, we create a FontUtils so that we could reuse it with different components
public class FontUtils {
public static int FONT_REGULAR = 0;
public static int FONT_THIN = 1;
public static void setTypeface (int fontName, TextView textView) {
Typeface font = null;
Context context = textView.getContext();
Resources resources = context.getResources();
if (fontName == FontUtils.FONT_REGULAR) {
font = Typeface.createFromAsset(context.getAssets(), resources.getString(R.string.font_regular));
} else if (fontName == FontUtils.FONT_THIN) {
font = Typeface.createFromAsset(context.getAssets(), resources.getString(R.string.font_thin));
}
textView.setTypeface(font);
}
}
The full class is here, basically here we create a helper class that would set the typeface based on the fontName that is passed from the xml. We create the typeface from the files we have under assets/ using the Typeface.createFromAsset(context.getAssets(), resources.getString(R.string.font_thin)); where the getString() will load the path of the string based on the locale we have. For example we passed in 0 (FONT_REGULAR) we would then load fonts/Roboto-Regular.ttf for English and fonts/NotoSansCJKtc-Bold.oft for Chinese.
For the custom class we have RadioButton as example but it could easily be done with EditText, CheckBox, Spinner using the prefix Tint
public class RadioButtonCustomFont extends TintRadioButton {
private int mFontName;
...
public RadioButtonCustomFont(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
...
private void init(AttributeSet attrs, int defStyle) {
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.font, defStyle, 0);
mFontName = a.getInt(R.styleable.font_name, FontUtils.FONT_REGULAR);
a.recycle();
if (!isInEditMode()) {
FontUtils.setTypeface(mFontName, this);
}
}
}
Here we just pass the mFontName to our FontUtils helper, we got that from the xml on our layout.
To create our RadioButtonCustomFont on our layout we must do something like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:font="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.monmonja.tutorial.RadioButtonCustomFont
font:name="Regular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Yes"
/>
</RelativeLayout>
Here we create a namespace for font (the same as the name in our assets.xml) then we pass in font:name the value/s from the assets.xml.
Finally we need to apply the tinting that comes with appcompat, for that take a look at the our themes.xml and its explanation is the same as Appcompat for pre-lollipop theming part
Hope this helps :)
No comments: