19 June, 2013

Custom fonts in Android (Part 2 of 3) - Setting font in xml

The objective is to have the following xml:

<?xml version="1.0" encoding="utf-8"?>
<com.demo.LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:control="http://schemas.android.com/apk/res/com.demo"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.demo.CustomFontTextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        control:customFont="fonts/Roboto-Light.ttf" />

</com.demo.LinearLayout>

To enable this we need to declare a custom attribute in values\attrs.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    
    <declare-styleable name="CustomFontView">
        <attr name="customFont" format="string" />
    </declare-styleable>

</resources>
Now we can add the control namespace as seen in the first snippet in line 4.
To read the customFont value and actually apply it to the TextView we're going to extend it and read the new attribute. The CustomFontTextView could be something like this:

public class CustomFontTextView extends TextView {

 public CustomFontTextView(Context context, AttributeSet attrs) {

  super(context, attrs);
  setCustomFont(context, this, attrs);
 }
 
 public void setCustomFont(Context context, TextView view, AttributeSet attrs) {

  TypedArray styleAttrs = context.obtainStyledAttributes(attrs, R.styleable.CustomFontView);
  String customFont = styleAttrs.getString(R.styleable.CustomFontView_customFont);
  setCustomFont(context, view, customFont);
  styleAttrs.recycle();
 }
}
Just like this CustomFontTextView, the same method can be applied to all views. To apply to multiple views inside a complex view check Arnaud's answer in http://stackoverflow.com/questions/9797872/use-roboto-font-for-earlier-deviceshttp://stackoverflow.com/questions/9797872/use-roboto-font-for-earlier-devices.

To avoid having the same path copied all over your xml files you may consider creating styles and put the path there.

<style name="RobotoTextView" parent="android:Widget.Holo.Light.TextView">
 <item name="customFont">fonts/Roboto-Bold.ttf</item>
</style>
And then applying that style in your custom controls:
    <com.demo.CustomFontTextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        style="@style/RobotoTextView" />
On the last part we will focus on a memory leak you may find and how to avoid it.