I have added a custom font file to my assets/fonts folder. How do I use it from my XML?
I can use it from code as follows:
TextView text = (TextView) findViewById(R.id.textview03);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf");
text.setTypeface(tf);
Can't I do it from XML using an android:typeface="/fonts/Molot.otf"
attribute?
Short answer: No. Android doesn't have built-in support for applying custom fonts to text widgets through XML.
However, there's a workaround that's not terribly difficult to implement.
First
You'll need to define your own stylable. In your /res/values folder, open/create the attrs.xml file and add a declare-styleable object like so:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FontText">
<attr name="typefaceAsset" format="string"/>
</declare-styleable>
</resources>
Second
Assuming you want to use this widget often, you should set up a simple cache for the loaded Typeface
objects, since loading them from memory on the fly can take time. Something like:
public class FontManager {
private static FontManager instance;
private AssetManager mgr;
private Map<String, Typeface> fonts;
private FontManager(AssetManager _mgr) {
mgr = _mgr;
fonts = new HashMap<String, Typeface>();
}
public static void init(AssetManager mgr) {
instance = new FontManager(mgr);
}
public static FontManager getInstance() {
if (instance == null) {
// App.getContext() is just one way to get a Context here
// getContext() is just a method in an Application subclass
// that returns the application context
AssetManager assetManager = App.getContext().getAssets();
init(assetManager);
}
return instance;
}
public Typeface getFont(String asset) {
if (fonts.containsKey(asset))
return fonts.get(asset);
Typeface font = null;
try {
font = Typeface.createFromAsset(mgr, asset);
fonts.put(asset, font);
} catch (Exception e) {
}
if (font == null) {
try {
String fixedAsset = fixAssetFilename(asset);
font = Typeface.createFromAsset(mgr, fixedAsset);
fonts.put(asset, font);
fonts.put(fixedAsset, font);
} catch (Exception e) {
}
}
return font;
}
private String fixAssetFilename(String asset) {
// Empty font filename?
// Just return it. We can't help.
if (TextUtils.isEmpty(asset))
return asset;
// Make sure that the font ends in '.ttf' or '.ttc'
if ((!asset.endsWith(".ttf")) && (!asset.endsWith(".ttc")))
asset = String.format("%s.ttf", asset);
return asset;
}
}
This one will allow you to use .ttc file extensions, but it's untested.
Third
Create a new class that subclasses TextView
. This particular example takes into account the defined XML typeface (bold
, italic
, etc.) and apply it to the font (assuming you're using a .ttc file).
/**
* TextView subclass which allows the user to define a truetype font file to use as the view's typeface.
*/
public class FontText extends TextView {
public FontText(Context context) {
this(context, null);
}
public FontText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FontText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (isInEditMode())
return;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FontText);
if (ta != null) {
String fontAsset = ta.getString(R.styleable.FontText_typefaceAsset);
if (!TextUtils.isEmpty(fontAsset)) {
Typeface tf = FontManager.getInstance().getFont(fontAsset);
int style = Typeface.NORMAL;
float size = getTextSize();
if (getTypeface() != null)
style = getTypeface().getStyle();
if (tf != null)
setTypeface(tf, style);
else
Log.d("FontText", String.format("Could not create a font from asset: %s", fontAsset));
}
}
}
}
Finally
Replace the instances of TextView
in your XML with the fully qualified class name. Declare your custom namespace just like you would the Android namespace. Note that the "typefaceAsset" should point to a .ttf or .ttc file contained in your /assets directory.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.FontText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is a custom font text"
custom:typefaceAsset="fonts/AvenirNext-Regular.ttf"/>
</RelativeLayout>