Add custom font for complete android application

57,527

Solution 1

I figured it out by my self. This is the code I used. I create custom TextView which has custom font as default font.

public class MyTextView extends TextView {

    public MyTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyTextView(Context context) {
        super(context);
        init();
    }

    private void init() {
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "font/chiller.ttf");
        setTypeface(tf ,1);

    }

}

Solution 2

In your activities, right after you call

setContentView(R.id.blahblah);

you should run a method to go over the whole hierarchy of widgets and deal with the font substitution, like;

setContentView(R.id.blahblah);
Utils.overrideFonts(this, findViewById(android.R.id.content));

And the mentioned "overrideFonts" method should be something like;

public static void overrideFonts(final Context context, final View v) {
    try {
        if (v instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                View child = vg.getChildAt(i);
                overrideFonts(context, child);
            }
        } else if (v instanceof TextView) {
            ((TextView)v).setTypeface(FONT_REGULAR);
        }
    } catch (Exception e) {
        e.printStackTrace();
        // ignore
    }
}

In this scheme, FONT_REGULAR should be initialized somewhere safely, you may fancy a singleton or some other way to be sure that it is initialized properly...

private static void initializeFonts(final Context context) {
    FONT_REGULAR = Typeface.createFromAsset(context.getAssets(), "fonts/myfont_medium.otf");
    FONT_BOLD = Typeface.createFromAsset(context.getAssets(), "fonts/myfont_bold.otf");
}

If you use a subclass of Activity like MyAppActivity (extends Activity), then you dont need to change each and every Activity class for such customizations. Instead you may cut into it and override the behavior as such;

public class MyAppActivity extends Activity {
... ...
    @Override
    public void setContentView(final int layoutResID) {
        super.setContentView(layoutResID);
        Utils.overrideFonts(this, findViewById(android.R.id.content));
    }
... ...
}

This way you can use any activity of yours to have common behavior;

public class SettingsUI extends MyAppActivity {
... ...
} 

I hope it helps... Cheers!

Solution 3

create a style and use it all text attributes.

<style name="CustomText">
    <item name="android:typeface">YourFontName</item>
</style>

Use it:

<TextView style="@style/CustomText" />

Above is to use custom fonts in all activity for customization you can use....

Typeface font = Typeface.createFromAsset(getAssets(), "CustomFontName.ttf");  
txt.setTypeface(font);

TRy this.

Solution 4

To apply custom font across all application, just create following activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    FontManager.getInstance().initialize(this, R.xml.fonts);
    setContentView(R.layout.main);
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    SimpleFactory factory = new SimpleFactory();
    return factory.onCreateView(name, context, attrs);
}

where FontManager this is class that manage all Fonts that defined in /xml/fonts.xml and SimpleFactory just factory that create views and apply custom font to each view that instance of text view.

/xml/fonts.xml

<?xml version="1.0" encoding="utf-8"?>
<familyset>
    <family>
        <nameset>
            <!--Font name-->
            <name>HelveticaNeueLTStd</name>
        </nameset>
        <fileset>
            <!--Font styles-->
            <file style="normal">fonts/HelveticaNeueLTStd-LtCn.otf</file>
            <file style="bold">fonts/HelveticaNeueLTStd-MdCn.otf</file>
            <file style="italic">fonts/HelveticaNeueLTStd-LtCnO.otf</file>
            <file style="bold_italic">fonts/HelveticaNeueLTStd-MdCnO.otf</file>
        </fileset>
    </family>
    <family>
        <!--There new font family can be added,
don't forget add font files into /assets/fonts directory and
put the name of the font into /values/string/font.xml-->
    </family>
</familyset>

FontFactory - abastract class, just extends it to create your own factory

public abstract class FontFactory implements LayoutInflater.Factory{
    public final String TAG = getClass().getSimpleName();

    static final Class<?>[] mConstructorSignature = new Class[] {Context.class, AttributeSet.class};
    final Object[] mConstructorArgs = new Object[2];
    private static final String[] sClassPrefixList = {
            "android.widget.",
            "android.webkit."
    };

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        if("ViewStub".equals(name) || "View".equals(name)){
            return null;
        }
        View view = null;
        Constructor<? extends View> constructor = null;
        Class clazz = null;

        if (view == null) {
            if (-1 == name.indexOf('.')) {
                for (String prefix : sClassPrefixList) {
                    clazz = getClazz(prefix, name);
                    if(clazz != null){
                        break;
                    }
                }
            } else {
                clazz = getClazz("", name);
            }
        }

        if (clazz == null) {
            Log.d(TAG, "View can't be created " + name);
            return null;
        }

        try {
            constructor = clazz.getConstructor(mConstructorSignature);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        Object[] args = mConstructorArgs;
        args[1] = attrs;

        if(constructor == null){
            return null;
        }

        try {
                view = constructor.newInstance(context, attrs);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        if(view != null){
            onFontApply(context, view);
        }
        return view;
    }

    public abstract void onFontApply(Context context, View view);

    private Class getClazz(String prefix, String name){
        Class clazz = null;
        try {
            clazz = Class.forName(prefix + name);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            return clazz;
        }
    }
}

FontManager - just map font files defined in /xml/fonts.xml to font files placed in /assets directory and return TypeFace by font family name and font style.

public void initialize(Context context, int resId) {
    if(mFonts != null){
        Log.d(TAG,"FontManager have already initialized");
        return;
    }
    XmlResourceParser parser = null;
    try {
        parser = context.getResources().getXml(resId);
        mFonts = new ArrayList<Font>();

        String tag;
        String fontStryleAttr = null;
        int eventType = parser.getEventType();

        Font font = null;

        do {
            tag = parser.getName();

            switch (eventType) {
                case XmlPullParser.START_TAG:
                    if (tag.equals(TAG_FAMILY)) {
                        // one of the font-families.
                        font = new Font();
                    } else if (tag.equals(TAG_NAMESET)) {
                        // a list of font-family names supported.
                        font.families = new ArrayList<String>();
                    } else if (tag.equals(TAG_NAME)) {
                        isName = true;
                    } else if (tag.equals(TAG_FILESET)) {
                        // a list of files specifying the different styles.
                        font.styles = new ArrayList<FontStyle>();
                    } else if (tag.equals(TAG_FILE)) {
                        isFile = true;
                        fontStryleAttr = parser.getAttributeValue(null, ATTR_STYLE);
                    }
                    break;

                case XmlPullParser.END_TAG:
                    if (tag.equals(TAG_FAMILY)) {
                        // add it to the list.
                        if (font != null) {
                            mFonts.add(font);
                            font = null;
                        }
                    } else if (tag.equals(TAG_NAME)) {
                        isName = false;
                    } else if (tag.equals(TAG_FILE)) {
                        isFile = false;
                        fontStryleAttr = null;
                    }
                    break;

                case XmlPullParser.TEXT:
                    String text = parser.getText();
                    if (isName) {
                        // value is a name, add it to list of family-names.
                        if (font.families != null)
                            font.families.add(text);
                    } else if (isFile) {
                        // value is a file, add it to the proper kind.
                        FontStyle fontStyle = new FontStyle();
                        fontStyle.font = Typeface.createFromAsset(context.getAssets(), text);
                        String attr = parser.getAttributeValue(null, ATTR_STYLE);
                        if (fontStryleAttr.equals(STYLE_BOLD))
                            fontStyle.style = Typeface.BOLD;
                        else if (fontStryleAttr.equals(STYLE_ITALIC))
                            fontStyle.style = Typeface.ITALIC;
                        else if (fontStryleAttr.equals(STYLE_BOLD_ITALIC))
                            fontStyle.style = Typeface.BOLD_ITALIC;
                        else
                            fontStyle.style = Typeface.NORMAL;
                        font.styles.add(fontStyle);
                    }
            }

            eventType = parser.next();

        } while (eventType != XmlPullParser.END_DOCUMENT);

    } catch (XmlPullParserException e) {
        throw new InflateException("Error inflating font XML", e);
    } catch (IOException e) {
        throw new InflateException("Error inflating font XML", e);
    } finally {
        if (parser != null)
            parser.close();
    }
}

public Typeface get(String family, int style) {
    for (Font font: mFonts) {
        for (String familyName : font.families) {
            if (familyName.equals(family)) {
                // if no style in specified, return normal style.
                if (style == -1)
                    style = Typeface.NORMAL;
                for (FontStyle fontStyle : font.styles) {
                    if (fontStyle.style == style)
                        return fontStyle.font;
                }
            }
        }
    }
    return mDefaultFont;
}

for more code and samples just look here

Share:
57,527
Chrishan
Author by

Chrishan

Experienced Android Developer. Please find my profile at LinkedIn

Updated on February 07, 2020

Comments

  • Chrishan
    Chrishan about 4 years

    In my application I need to use helvetica font for all the textviews and edit-text fields. Is there any way to do this other than using settypeface method for every textview ? Any suggestion would be a great help.

    Thanks in advance !

  • Chrishan
    Chrishan over 12 years
    android:typeface field only allow to use inbuilt font names. How can I assign custom font name which is in asset folder ?
  • Chrishan
    Chrishan about 12 years
    @mxg I didn't get what you said
  • Maggie
    Maggie over 11 years
    This is a good solution for simple layouts. However, if you have a ListView in your activity, this will not work. Items in the ListView are instantiated after setContent method and therefore, TextView in the list will not be affected by this method
  • lithium
    lithium over 11 years
    you are right, those need to be handled in the ...ItemAdapter class
  • Bill Mote
    Bill Mote over 11 years
    @mxg by overriding TextView he's able to use MyTextView in his layout files without having to do anything programmatically in the activity/fragment to realize the custom font.
  • Bill Mote
    Bill Mote over 11 years
    @hanry You cannot use a custom font name in the android:typeface field. The 2nd part of your answer will work, but the styles portion will not.
  • Milton
    Milton about 11 years
    Here is a good tutorial for this: barebonescoder.com/2010/05/…. If you want to consider different font family types, like bold or italic, you will use different ttf files. The way you can handle that is to ask for this.getTypeface().getStyle() in init method, and use different fonts for the textview. HTH
  • AlikElzin-kilaka
    AlikElzin-kilaka over 10 years
    What about the font of the actionbar?
  • Chrishan
    Chrishan over 10 years
    Why we need add some jar to do what we can purely do with Android itself?
  • odemolliens
    odemolliens over 10 years
    You can't use custom fonts with Android SDK
  • Benjamin Piette
    Benjamin Piette over 9 years
    This doesn't answer the question. "Is there any way to do this other than using settypeface method for every textview?".
  • Simas
    Simas almost 9 years
    TextViews inside fragments won't get their typefaces modified either.
  • prateek
    prateek over 8 years
    all i can see on link above is ads and related links with no content only ads