ChatGPT解决这个技术问题 Extra ChatGPT

How to change the font on the TextView?

How to change the font in a TextView, as default it's shown up as Arial? How to change it to Helvetica?

I think this is a repeat question. Look here for answer stackoverflow.com/questions/2878882/android-develop-lcd-font/…
may be my link helpful for you stackoverflow.com/questions/2376250/…

P
Prejith P

First, the default is not Arial. The default is Droid Sans.

Second, to change to a different built-in font, use android:typeface in layout XML or setTypeface() in Java.

Third, there is no Helvetica font in Android. The built-in choices are Droid Sans (sans), Droid Sans Mono (monospace), and Droid Serif (serif). While you can bundle your own fonts with your application and use them via setTypeface(), bear in mind that font files are big and, in some cases, require licensing agreements (e.g., Helvetica, a Linotype font).

EDIT

The Android design language relies on traditional typographic tools such as scale, space, rhythm, and alignment with an underlying grid. Successful deployment of these tools is essential to help users quickly understand a screen of information. To support such use of typography, Ice Cream Sandwich introduced a new type family named Roboto, created specifically for the requirements of UI and high-resolution screens. The current TextView framework offers Roboto in thin, light, regular and bold weights, along with an italic style for each weight. The framework also offers the Roboto Condensed variant in regular and bold weights, along with an italic style for each weight.

After ICS, android includes Roboto fonts style, Read more Roboto

EDIT 2

With the advent of Support Library 26, Android now supports custom fonts by default. You can insert new fonts in res/fonts which can be set to TextViews individually either in XML or programmatically. The default font for the whole application can also be changed by defining it styles.xml The android developer documentation has a clear guide on this here


No way to set fonts in XML? Why?
@Jonny You actually can. You're creating a class that extends TextView and calls setTypeface from the constructor.
how to do it in XML Layout?
@usman: You would need a third-party library, like Calligraphy: github.com/chrisjenx/Calligraphy
Setting typeface using java code is hard due to multiple lines, I have created a library to set custom fonts. You can find a library usage in this answer stackoverflow.com/a/42001474/4446392
S
Suragch

First download the .ttf file of the font you need (arial.ttf). Place it in the assets folder. (Inside assets folder create new folder named fonts and place it inside it.) Use the following code to apply the font to your TextView:

Typeface type = Typeface.createFromAsset(getAssets(),"fonts/arial.ttf"); 
textView.setTypeface(type);

Dear Mayur, Any recommendation on where to get these .ttf files?
Dear @lonelearner you can download free fonts (.ttf) files in 1001freefonts.com or just google "Free fonts"
For those using Android Studio and can't find an "assets" folder, see this question. Short answer: src/main/assets/fonts/.
A
Android Girl
Typeface tf = Typeface.createFromAsset(getAssets(),
        "fonts/DroidSansFallback.ttf");
TextView tv = (TextView) findViewById(R.id.CustomFontText);
tv.setTypeface(tf);

D
Daniel L.

You might want to create static class which will contain all the fonts. That way, you won't create the font multiple times which might impact badly on performance. Just make sure that you create a sub-folder called "fonts" under "assets" folder.

Do something like:

public class CustomFontsLoader {

public static final int FONT_NAME_1 =   0;
public static final int FONT_NAME_2 =   1;
public static final int FONT_NAME_3 =   2;

private static final int NUM_OF_CUSTOM_FONTS = 3;

private static boolean fontsLoaded = false;

private static Typeface[] fonts = new Typeface[3];

private static String[] fontPath = {
    "fonts/FONT_NAME_1.ttf",
    "fonts/FONT_NAME_2.ttf",
    "fonts/FONT_NAME_3.ttf"
};


/**
 * Returns a loaded custom font based on it's identifier. 
 * 
 * @param context - the current context
 * @param fontIdentifier = the identifier of the requested font
 * 
 * @return Typeface object of the requested font.
 */
public static Typeface getTypeface(Context context, int fontIdentifier) {
    if (!fontsLoaded) {
        loadFonts(context);
    }
    return fonts[fontIdentifier];
}


private static void loadFonts(Context context) {
    for (int i = 0; i < NUM_OF_CUSTOM_FONTS; i++) {
        fonts[i] = Typeface.createFromAsset(context.getAssets(), fontPath[i]);
    }
    fontsLoaded = true;

}
}

This way, you can get the font from everywhere in your application.


Awesome dude! This is the beauty of OOP. Great work! :)
How do I use this class?
You need to place this code in your project, adapt it to your fonts and then use the getTypeface(..) static method from everywhere in your app.
I used a similar solution, but added caching to improve performance.... in any case, did you encounter a situation where the font works on some phones and doesn't in others?
H
Hiren Patel

Best practice ever

TextViewPlus.java:

public class TextViewPlus extends TextView {
    private static final String TAG = "TextView";

    public TextViewPlus(Context context) {
        super(context);
    }

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

    public TextViewPlus(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.TextViewPlus);
        String customFont = a.getString(R.styleable.TextViewPlus_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String asset) {
        Typeface typeface = null;
        try {
            typeface = Typeface.createFromAsset(ctx.getAssets(), asset);
        } catch (Exception e) {
            Log.e(TAG, "Unable to load typeface: "+e.getMessage());
            return false;
        }

        setTypeface(typeface);
        return true;
    }
}

attrs.xml: (Where to place res/values)

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

How to use:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:foo="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.mypackage.TextViewPlus
        android:id="@+id/textViewPlus1"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:text="@string/showingOffTheNewTypeface"
        foo:customFont="my_font_name_regular.otf">
    </com.mypackage.TextViewPlus>
</LinearLayout>

Hope this will help you.


Why is subclassing TextView the best practice?
@Stealth Rabbi, here we can pass custom font by xml only, no need to write special java code for each textview.
There is library for that. Simply add your font under asset folder and declare it in XML. github.com/febaisi/CustomTextView
Your library looks fine, but the only problem is that it is for android 21+
V
VJ Vélan Solutions

The answers above are correct. Just make sure that you create a sub-folder called "fonts" under "assets" folder if you are using that piece of code.


Your comment is redundant. The above explanation says exactly what you said, and more...
C
Chris Aitchison

Another way to consolidate font creation...

public class Font {
  public static final Font  PROXIMA_NOVA    = new Font("ProximaNovaRegular.otf");
  public static final Font  FRANKLIN_GOTHIC = new Font("FranklinGothicURWBoo.ttf");
  private final String      assetName;
  private volatile Typeface typeface;

  private Font(String assetName) {
    this.assetName = assetName;
  }

  public void apply(Context context, TextView textView) {
    if (typeface == null) {
      synchronized (this) {
        if (typeface == null) {
          typeface = Typeface.createFromAsset(context.getAssets(), assetName);
        }
      }
    }
    textView.setTypeface(typeface);
  }
}

And then to use in your activity...

myTextView = (TextView) findViewById(R.id.myTextView);
Font.PROXIMA_NOVA.apply(this, myTextView);

Mind you, this double-checked locking idiom with the volatile field only works correctly with the memory model used in Java 1.5+.


Why does this answer only have 1 upvote and the one above have 15? What makes the other one better ? Seems to me this one is the more straight-forward using the singleton principle ... ?
Just saw that you have your constructor public, i'd make it private since you don't need any acces to it. You're using your inner Font vars anyways...
Absolutely should be private constructor. Well spotted :) Will edit!
M
Marek Rzeźniczek

Best practice is to use Android Support Library version 26.0.0 or above.

STEP 1: add font file

In res folder create new font resource dictionary Add font file (.ttf, .orf)

For example, when font file will be helvetica_neue.ttf that will generates R.font.helvetica_neue

STEP 2: create font family

In font folder add new resource file Enclose each font file, style, and weight attribute in the element.

For example:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font
        android:fontStyle="normal"
        android:fontWeight="400"
        android:font="@font/helvetica_neue" />
</font-family>

STEP 3: use it

In xml layouts:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:fontFamily="@font/my_font"/>

Or add fonts to style:

<style name="customfontstyle" parent="@android:style/TextAppearance.Small">
    <item name="android:fontFamily">@font/lobster</item>
</style>

For more examples you can follow documentation:

Working with fonts


P
Pankaj Lilan

When your font is stored inside res/asset/fonts/Helvetica.ttf use the following:

Typeface tf = Typeface.createFromAsset(getAssets(),"fonts/Helvetica.ttf"); 
txt.setTypeface(tf);

Or, if your font file is stores inside res/font/helvetica.ttf use the following:

Typeface tf = ResourcesCompat.getFont(this,R.font.helvetica);
txt.setTypeface(tf);

Thanks, were looking for the part where you had it in the res folder!
A
Alan

It's a little old, but I improved the class CustomFontLoader a little bit and I wanted to share it so it can be helpfull. Just create a new class with this code.

 import android.content.Context;
 import android.graphics.Typeface;

public enum FontLoader {

ARIAL("arial"),
TIMES("times"),
VERDANA("verdana"),
TREBUCHET("trbuchet"),
GEORGIA("georgia"),
GENEVA("geneva"),
SANS("sans"),
COURIER("courier"),
TAHOMA("tahoma"),
LUCIDA("lucida");   


private final String name;
private Typeface typeFace;


private FontLoader(final String name) {
    this.name = name;

    typeFace=null;  
}

public static Typeface getTypeFace(Context context,String name){
    try {
        FontLoader item=FontLoader.valueOf(name.toUpperCase(Locale.getDefault()));
        if(item.typeFace==null){                
            item.typeFace=Typeface.createFromAsset(context.getAssets(), "fonts/"+item.name+".ttf");                 
        }           
        return item.typeFace;
    } catch (Exception e) {         
        return null;
    }                   
}
public static Typeface getTypeFace(Context context,int id){
    FontLoader myArray[]= FontLoader.values();
    if(!(id<myArray.length)){           
        return null;
    } 
    try {
        if(myArray[id].typeFace==null){     
            myArray[id].typeFace=Typeface.createFromAsset(context.getAssets(), "fonts/"+myArray[id].name+".ttf");                       
        }       
        return myArray[id].typeFace;    
    }catch (Exception e) {          
        return null;
    }   

}

public static Typeface getTypeFaceByName(Context context,String name){      
    for(FontLoader item: FontLoader.values()){              
        if(name.equalsIgnoreCase(item.name)){
            if(item.typeFace==null){
                try{
                    item.typeFace=Typeface.createFromAsset(context.getAssets(), "fonts/"+item.name+".ttf");     
                }catch (Exception e) {          
                    return null;
                }   
            }
            return item.typeFace;
        }               
    }
    return null;
}   

public static void loadAllFonts(Context context){       
    for(FontLoader item: FontLoader.values()){              
        if(item.typeFace==null){
            try{
                item.typeFace=Typeface.createFromAsset(context.getAssets(), "fonts/"+item.name+".ttf");     
            }catch (Exception e) {
                item.typeFace=null;
            }   
        }                
    }       
}   
}

Then just use this code on you textview:

 Typeface typeFace=FontLoader.getTypeFace(context,"arial");  
 if(typeFace!=null) myTextView.setTypeface(typeFace);

S
Shamsul Arefin Sajib

I finally got a very easy solution to this.

use these Support libraries in app level gradle, compile 'com.android.support:appcompat-v7:26.0.2' compile 'com.android.support:support-v4:26.0.2' then create a directory named "font" inside the res folder put fonts(ttf) files in that font directory, keep in mind the naming conventions [e.g.name should not contain any special character, any uppercase character and any space or tab] After that, reference that font from xml like this

C
Charlie-Blake
import java.lang.ref.WeakReference;
import java.util.HashMap;

import android.content.Context;
import android.graphics.Typeface;

public class FontsManager {

    private static FontsManager instance;

    private static HashMap<String, WeakReference<Typeface>> typefaces = new HashMap<String, WeakReference<Typeface>>();

    private static Context context;

    private FontsManager(final Context ctx) {
        if (context == null) {
            context = ctx;
        }
    }

    public static FontsManager getInstance(final Context appContext) {
        if (instance == null) {
            instance = new FontsManager(appContext);
        }
        return instance;
    }

    public static FontsManager getInstance() {
        if (instance == null) {
            throw new RuntimeException(
                    "Call getInstance(Context context) at least once to init the singleton properly");
        }
        return instance;
    }

    public Typeface getFont(final String assetName) {
        final WeakReference<Typeface> tfReference = typefaces.get(assetName);
        if (tfReference == null || tfReference.get() == null) {
            final Typeface tf = Typeface.createFromAsset(context.getResources().getAssets(),
                    assetName);
            typefaces.put(assetName, new WeakReference<Typeface>(tf));
            return tf;
        }
        return tfReference.get();
    }

}

This way, you can create a View which inherits from TextView and calls setTypeface on its constructor.


Hello, why are using WeakReference to hold TypeFace object?
M
Manian Rezaee

get font from asset and set to all children

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(Typeface.createFromAsset(context.getAssets(),"DroidNaskh.ttf"));// "BKOODB.TTF"));
        }
    } catch (Exception e) {
 }
 } 

a
alanHdez

add class FontTextView.java:

public class FontTextView extends TextView {
    String fonts[] = {"HelveticaNeue.ttf", "HelveticaNeueLight.ttf", "motschcc.ttf", "symbol.ttf"};

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

    public FontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (!isInEditMode()) {
            init(attrs);
        }

    }

    public FontTextView(Context context) {
        super(context);
        if (!isInEditMode()) {
            init(null);
        }
    }

    private void init(AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FontTextView);
            if (a.getString(R.styleable.FontTextView_font_type) != null) {
                String fontName = fonts[Integer.valueOf(a.getString(R.styleable.FontTextView_font_type))];

                if (fontName != null) {
                    Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "font/" + fontName);
                    setTypeface(myTypeface);
                }
                a.recycle();
            }
        }
    }
}

add to assets library font

add to attrs.xml , The numbers should be in the order in array class.

Select a font from the list


Do you need to instantiate this class in MainActivity? Because it's not changing anything for me.
C
Chandler

Android uses the Roboto font, which is a really nice looking font, with several different weights (regular, light, thin, condensed) that look great on high density screens.

Check below link to check roboto fonts:

How to use Roboto in xml layout

Back to your question, if you want to change the font for all of the TextView/Button in your app, try adding below code into your styles.xml to use Roboto-light font:

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    ......
    <item name="android:buttonStyle">@style/MyButton</item>
    <item name="android:textViewStyle">@style/MyTextView</item>
</style>

<style name="MyButton" parent="@style/Widget.AppCompat.Button">
    <item name="android:textAllCaps">false</item>
    <item name="android:fontFamily">sans-serif-light</item>
</style>

<style name="MyTextView" parent="@style/TextAppearance.AppCompat">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

And don't forget to use 'AppTheme' in your AndroidManifest.xml

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    ......
</application>

t
trans

Maybe something a bit simpler:

public class Fonts {
  public static HashSet<String,Typeface> fonts = new HashSet<>();

  public static Typeface get(Context context, String file) {
    if (! fonts.contains(file)) {
      synchronized (this) {
        Typeface typeface = Typeface.createFromAsset(context.getAssets(), name);
        fonts.put(name, typeface);
      }
    }
    return fonts.get(file);
  }
}

// Usage
Typeface myFont = Fonts.get("arial.ttf");

(Note this code is untested, but in general this approach should work well.)