4

Is there any way to pass custom font for TextView (or subclasses of it) using only xml without providing any java code like this

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/CustomFont.ttf");
s_id
  • 446
  • 3
  • 10

1 Answers1

5

It is not possible to do it purely from XML, but you can create a custom view and reference that from XML. This way you will only need to write the code once, allowing you to recycle it in various layouts.

For instance, declare the class FontTextView:

package com.example;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;

public class FontTextView extends TextView {

    /** 
     *  Note that when generating the class from code, you will need
     *  to call setCustomFont() manually.
     */
    public FontTextView(Context context) {
        super(context);
    }

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

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

    private void setCustomFont(Context context, AttributeSet attrs) {
        if (isInEditMode()) {
            // Ignore if within Eclipse
            return;
        }
        String font = "myDefaultFont.ttf";
        if (attrs != null) {
            // Look up any layout-defined attributes
            TypedArray a = obtainStyledAttributes(attrs,
                    R.styleable.FontTextView);
            for (int i = 0; i < a.getIndexCount(); i++) {
                int attr = a.getIndex(i);
                switch (attr) {
                case R.styleable.FontTextView_customFont:
                    font = a.getString(attr, 0);
                    break;
                }
            }
            a.recycle();
        }
        Typeface tf = null;
        try {
            tf = Typeface.createFromAsset(getAssets(), font);
        } catch (Exception e) {
            Log.e("Could not get typeface: " + e.getMessage());
        }
        setTypeface(tf);
    }

}

Define the attribute in res/values/attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>

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

</resources>

Use it in a layout:

  1. Declare the namespace:

    xmlns:custom="http://schemas.android.com/apk/res/com.example"
    
  2. Use the FontTextView:

    <com.example.FontTextView
        android:id="@+id/introduction"
        customFont="myCustomFont.ttf"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Hello world!" />
    
Paul Lammertsma
  • 37,593
  • 16
  • 136
  • 187
  • i'm sorry but what if i want to use Button or CheckedTextView or CompountButton or other i should make an extention for each of them? this doesn't a good solution sorry :-( – s_id Dec 07 '11 at 13:32
  • 2
    Generalize `setCustomFont()` into a static context, and if you're always using the XML constructor, you only need to define one constructor per view element. In practicality I've found only five or so different controls that I wanted to extend, and since you don't need any extra code around views or layouts, I've found it to be the best solution. – Paul Lammertsma Dec 07 '11 at 19:12
  • @s_id this is the best solution, other than adding some static caching so you don't have to load the Typeface every time you create a new FontTextView object.. – Tyler Jul 09 '12 at 23:02
  • @Styler Be careful with static fields. You might unintentionally keep the entire activity in memory. I would suggest extending the Application class and getting the Typeface through it. – Paul Lammertsma Jul 10 '12 at 10:48