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 =
The best solution is to use (finally) introduced by Google a native custom font feature in XML. But you have to target API 26. It supports API 16+
https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml
Create a fonts folder in assets and add all your required font's there.
public class CustomTextView extends TextView {
private static final String TAG = "TextView";
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
String customFont = a.getString(R.styleable.CustomTextView_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String fontName) {
Typeface typeface = null;
try {
if(fontName == null){
fontName = Constants.DEFAULT_FONT_NAME;
}
typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/" + fontName);
} catch (Exception e) {
Log.e(TAG, "Unable to load typeface: "+e.getMessage());
return false;
}
setTypeface(typeface);
return true;
}
}
and add a declarable in attrs.xml
<declare-styleable name="CustomTextView">
<attr name="customFont" format="string"/>
</declare-styleable>
and then add your customFont like
app:customFont="arial.ttf"
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>
I know this is an old question, but i've found a much easier solution.
First declare your TextView in xml as usual. Put your font (TTF or TTC) in the asset folder
app\src\main\assets\
Then just set the typeface for your text view in your onCreate method.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
TextView textView = findViewById(R.id.my_textView);
Typeface typeface = Typeface.createFromAsset(getAssets(), "fontName.ttf");
textView.setTypeface(typeface);
}
Done.
instead of xmlns:custom="schemas.android.com/tools"; you should use: xmlns:custom="schemas.android.com/apk/res-auto"; in order to use styleable attributes. I made this change and it is working now.
Activity implements LayoutInflater.Factory2 that provides callbacks on each created View. It's possible to style the TextView with custom font Family attribute, load the typefaces on demand and call setTypeface on instantiated text views automatically.
Unfortunately due to the architectural relationship of Inflater instances relative to Activities and Windows the simplest approach to use custom fonts in android is to cache loaded fonts on the Application level.
The sample code base is here:
https://github.com/leok7v/android-textview-custom-fonts
<style name="Baroque" parent="@android:style/TextAppearance.Medium">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#F2BAD0</item>
<item name="android:textSize">14pt</item>
<item name="fontFamily">baroque_script</item>
</style>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/custom.fonts"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
style="@style/Baroque"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sample_text"
/>
results in