Custom font Views/Controls in Android

Jimit Patel
5 min readApr 26, 2016

It has been time I made a custom view for TextView, Button, Checkbox, etc. in Android which supports different fonts which are not from default Android choices. According to CommonsWare, built-in choices are Droid Sans (sans), Droid Sans Mono (monospace), and Droid Serif (serif). But beyond that if one needs to use fonts which are not from mentioned fonts then what?

Well the solution is to this problem is the piece of code below. The first piece of code/class gives the typeface of the font and second piece of code is the method to set that typeface to the TextView.

public class FontCache {

private static Hashtable<String, Typeface> fontCache = new Hashtable<>();

/**
* Gets the typeface from Asset folder
*
@param name path to the font within asset folder
*
@param context context of the view
*
@return
*/
public static Typeface get(String name, Context context) {
Typeface tf = fontCache.get(name);
if (tf == null) {
try {
tf = Typeface.createFromAsset(context.getAssets(), name);
} catch (Exception e) {
return null;
}
fontCache.put(name, tf);
}
return tf;
}
}
/**
* Sets a font on a TextView
*
*
@param textview view for which font mentioned needs to be changed
*
@param font path of the font where it has been saved (Generally within asset folder)
*
@param context Context where view has been used
*/
public static void setCustomFont(TextView textview, String font, Context context) {
if (font == null) {
return;
}
Typeface typeface = FontCache.get(font, context);
if (typeface != null) {
textview.setTypeface(typeface);
}
}

You might be wondering why I have used HashTable in FontCache class. The use of the HashTable acts like caching element over here.

Of course, the above piece of code works well when one has TextView element in it. What if whole View is custom? I mean to say what if one has used paint for text, the java way of displaying? For that, the solution I found is and one can try with their eyes closed is as below

/**
* Changing font of Paint element
*
@param paint text element of which font needs to be changed
*
@param font
*
@param context
*/
public static void setCustomFont(Paint paint, String font, Context context) {
if (font == null) {
return;
}
Typeface typeface = FontCache.get(font, context);
if (typeface != null) {
paint.setTypeface(typeface);
}
}

Well this solves the problem. Didn’t it? Well it didn’t solved one of my problem. I am lazy to recode everything everywhere. I feared that my manager or designer tomorrow will tell me to change the font to some different one then as it is using as of now. If I did this then I don’t have to worry at all. Then I came up with solution which Android helps in making such code. It is none other than declare-styleable. Yes! it indeed solved my problem.

What I did is, in attrs.xml I made one attribute which accepts path to the font is asset folder.

<declare-styleable name="TextFont">
<attr name="customFont" format="string" />
</declare-styleable>

Then I created a class which handles this custom font named as CustomFontHelper.java

public class CustomFontHelper {
/**
* Sets a font on a textview based on the custom com.my.package:font attribute
* If the custom font attribute isn't found in the attributes nothing happens
*
*
@param textview
*
@param context
*
@param attrs
*/
public static void setCustomFont(TextView textview, Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextFont);
String font = typedArray.getString(R.styleable.TextFont_customFont);
setCustomFont(textview, font, context);
typedArray.recycle();
}

/**
* Sets a font on a TextView
*
*
@param textview view for which font mentioned needs to be changed
*
@param font path of the font where it has been saved (Generally within asset folder)
*
@param context Context where view has been used
*/
public static void setCustomFont(TextView textview, String font, Context context) {
if (font == null) {
return;
}
Typeface typeface = FontCache.get(font, context);
if (typeface != null) {
textview.setTypeface(typeface);
}
}

/**
* Sets a font on a paint based on the custom com.my.package:font attribute
* If the custom font attribute isn't found in the attributes nothing happens
*
*
@param paint
*
@param context
*
@param attrs
*/
public static void setCustomFont(Paint paint, Context context, AttributeSet attrs){
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextFont);
String font = typedArray.getString(R.styleable.TextFont_customFont);
setCustomFont(paint, font, context);
typedArray.recycle();
}

/**
* Changing font of Paint element
*
@param paint text element of which font needs to be changed
*
@param font
*
@param context
*/
public static void setCustomFont(Paint paint, String font, Context context) {
if (font == null) {
return;
}
Typeface typeface = FontCache.get(font, context);
if (typeface != null) {
paint.setTypeface(typeface);
}
}
}

This class checks the path from the attributes assigned in the custom view in layout file. Below are few sample of custom views

TextView

public class FontTextView extends TextView {

public FontTextView(Context context) {
super(context);
}

public FontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
CustomFontHelper.setCustomFont(this, context, attrs);
}

public FontTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
CustomFontHelper.setCustomFont(this, context, attrs);
}
}

EditText

public class FontEditText extends EditText {
public FontEditText(Context context) {
super(context);
}

public FontEditText(Context context, AttributeSet attrs) {
super(context, attrs);
CustomFontHelper.setCustomFont(this, context, attrs);
}

public FontEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
CustomFontHelper.setCustomFont(this, context, attrs);
}
}

Button

public class FontButton extends Button {

public FontButton(Context context) {
super(context);
}

public FontButton(Context context, AttributeSet attrs) {
super(context, attrs);
CustomFontHelper.setCustomFont(this, context, attrs);
}

public FontButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
CustomFontHelper.setCustomFont(this, context, attrs);
}
}

In Asset folder I have fonts saved already like this

Fonts in Asset folder

Then in string.xml file, I added following paths of the font-

<string name="font_light">fonts/SourceSansPro-Regular.ttf</string>
<string name="font_semibold">fonts/SourceSansPro-Semibold.ttf</string>
<string name="font_regular">fonts/SourceSansPro-Regular.ttf</string>
<string name="font_bold">fonts/Oxygen-Bold.ttf</string>

To see how this works in layout file then one of the example is as below-

<com.COMPANY.APP.app.custom.FontTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/lbl_welcome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/img_logo"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="YOUR SHOPPING COMPANION!"
android:textColor="@color/toolbar"
android:textSize="@dimen/font_12"
app:customFont="@string/font_semibold" />
This is how it looks on app

I hope this will be useful stuff for each Android developer

--

--