我需要为整个应用程序使用某些字体。我有相同的.ttf文件。
是否可以在应用程序启动时将此字体设置为默认字体,然后在应用程序中的其他位置使用它?设置后,如何在布局XML中使用它?

评论

在android studio 3.0中,您可以轻松设置自定义字体:developer.android.com/guide/topics/ui/look-and-feel / ...

XML中的@MHSFisher字体是Android 8.0(API级别26)的功能。

@EmiRaz请阅读文档developer.android.com/guide/topics/ui/look-and-feel/…。此功能已添加到支持库26中,但来自API 16的支持。

#1 楼

是的,反思。这有效(基于此答案):

(注意:由于缺乏对自定义字体的支持,因此这是一种解决方法,因此,如果您要更改此情况,请加注星标以投票给android在这里发行)。注意:请勿在该问题上留下“我也”评论,当您这样做时,所有盯着它的人都会收到一封电子邮件。因此,只需“加星号”即可。

import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;

public final class FontsOverride {

    public static void setDefaultFont(Context context,
            String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(),
                fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    }

    protected static void replaceFont(String staticTypefaceFieldName,
            final Typeface newTypeface) {
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField(staticTypefaceFieldName);
            staticField.setAccessible(true);
            staticField.set(null, newTypeface);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}


然后您需要重载一些默认字体,例如在应用程序类中:

public final class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();
        FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
        FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
        FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
        FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
    }
}


或者当然,如果您使用的是相同的字体文件,则可以对此进行改进以仅将其加载一次。

但是我倾向于只覆盖一个,例如"MONOSPACE",然后设置一种样式来强制字体字体应用程序广泛使用:

<resources>
    <style name="AppBaseTheme" parent="android:Theme.Light">
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <item name="android:typeface">monospace</item>
    </style>
</resources>


API 21 Android 5.0

我已经研究了注释它无效,并且似乎与主题android:Theme.Material.Light不兼容。

如果该主题对您不重要,请使用较旧的主题,例如:

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
    <item name="android:typeface">monospace</item>
</style>


评论


您将如何覆盖等宽粗体或斜体?

–克里斯托弗·里维拉(Christopher Rivera)
2014年3月26日19:01



@ChristopherRivera有“ DEFAULT_BOLD”但还有一个私有字段:private static Typeface [] sDefaults;您可以尝试通过反射并将sDefaults [Typeface.ITALIC]设置为yourTypeface来访问它。看到这个。

–weston
2014年3月27日9:17



@weston没关系。我已经做到了。我的理解有误。你已经做了很多工作。你能告诉我一件事吗?为什么它不适用于DEFAULT字体?我已将Typeface更改为MONOSPACE作为您的建议,然后应用loginc,它起作用了。但不适用于DEFAULT

–杰伊·潘迪(Jay Pandya)
2014年11月29日,下午3:56

无法使本机字体出错。固定,通过添加字体路径。 “ FontsOverride.setDefaultFont(this,” DEFAULT“,” fonts / MyFontAsset.ttf“);”

–西
2015年1月10日,下午4:06

我发现必须到处换出默认TextView来使用自定义字体或使用基于反射的解决方案真的很烦。结合android中可用的字体限制集,它使开发美观的应用程序变得很辛苦。我已向Android问题跟踪器添加了功能请求。如果您想使用此功能,可以在此处加注星标:code.google.com/p/android/issues/…

–山姆
2015年9月25日上午10:06

#2 楼

android中有一个很棒的自定义字体库:Calligraphy

这里有一个使用示例。

在Gradle中,您需要将此行放入应用程序的build.gradle文件中:

dependencies {
    compile 'uk.co.chrisjenx:calligraphy:2.2.0'
}


,然后创建一个扩展Application和编写此代码:

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
                        .setDefaultFontPath("your font path")
                        .setFontAttrId(R.attr.fontPath)
                        .build()
        );
    }
} 


,然后在活动类中将此方法放在onCreate之前:

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}


,清单文件的最后一件事应该是这样的:

<application
   .
   .
   .
   android:name=".App">


,它将把整个活动更改为您的字体!简单干净!

评论


这是完美的解决方案。

– nizam.sp
16年2月25日在9:57

没错,这是非常完美的解决方案,通过这种方式,我不必编写其他类来更新菜单项,单选按钮或复选框字体的字体。它适用于所有!谢谢 :)

– Manisha
16年4月15日在22:38

绝对不是完美的解决方案:粗体/斜体/粗斜体样式被覆盖。当前没有简单的方法来设置这些家庭。

–0101100101
16年5月11日在8:37

如果这样做,如何从粗体切换为常规?

– GMX
17年1月19日在21:41

为了获得粗体,斜体或下划线功能,我在strings.xml文件中使用了 ,到目前为止,它仍然有效。

– jlively
17 Mar 25 '17 at 22:53

#3 楼

虽然这不适用于整个应用程序,但适用于一个活动,并且可以重新用于任何其他活动。我已经更新了我的代码,这要感谢@ FR073N以支持其他视图。我不确定ButtonsRadioGroups等问题,因为这些类都扩展了TextView,所以它们应该可以正常工作。我添加了一个使用反射的布尔条件,因为它看起来很黑,可能会显着降低性能。

注意:如前所述,这不适用于动态内容!为此,可以使用onCreateViewgetView方法来调用此方法,但需要付出额外的努力。

/**
 * Recursively sets a {@link Typeface} to all
 * {@link TextView}s in a {@link ViewGroup}.
 */
public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{
    if (mContainer == null || mFont == null) return;

    final int mCount = mContainer.getChildCount();

    // Loop through all of the children.
    for (int i = 0; i < mCount; ++i)
    {
        final View mChild = mContainer.getChildAt(i);
        if (mChild instanceof TextView)
        {
            // Set the font if it is a TextView.
            ((TextView) mChild).setTypeface(mFont);
        }
        else if (mChild instanceof ViewGroup)
        {
            // Recursively attempt another ViewGroup.
            setAppFont((ViewGroup) mChild, mFont);
        }
        else if (reflect)
        {
            try {
                Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
                mSetTypeface.invoke(mChild, mFont); 
            } catch (Exception e) { /* Do something... */ }
        }
    }
}


然后使用它,您将执行以下操作:

final Typeface mFont = Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf"); 
final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, mFont);


希望有帮助。

评论


我认为最好的方法是重写textview。如果您的应用程序具有很多视图,则此方法可能会有些多余。

–zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
2012年7月9日下午0:36

可以...但是,根据Android规范,您要避免布局深度超过4个级别,且视图宽度不得超过100个(即使这样也是如此)。递归在性能方面可能很差,但是即使您的布局是20个级别,这也并不重要。

–汤姆
2012年7月9日下午0:52

我同意这不会对性能产生明显影响,我并不是要说您的答案是错误的。如果不需要,我只是不喜欢在布局中的每个视图之间循环。同样,通过扩展TextView,如果您想以另一种方式修改外观,则只需在一个位置更改代码。

–zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
2012年7月9日,1:11

只是想补充一下,上面的代码仅涵盖TextViews,但ListViews,Alerts,Toasts,Map Markers等仍将使用系统字体。

– csch
13年5月2日在10:50

伙计们,这个函数需要3个参数,当您递归调用它时,您传递了2个参数?哪个是正确的?什么是反映?

– MBH
2015年7月30日在17:01



#4 楼

总结:

选项1:使用反射来应用字体(结合weston和Roger Huang的答案):

import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;

public final class FontsOverride { 

    public static void setDefaultFont(Context context,
            String staticTypefaceFieldName, String fontAssetName) {
        final Typeface regular = Typeface.createFromAsset(context.getAssets(),
                fontAssetName);
        replaceFont(staticTypefaceFieldName, regular);
    } 

    protected static void replaceFont(String staticTypefaceFieldName,final Typeface newTypeface) {
        if (isVersionGreaterOrEqualToLollipop()) {
            Map<String, Typeface> newMap = new HashMap<String, Typeface>();
            newMap.put("sans-serif", newTypeface);
            try {
                final Field staticField = Typeface.class.getDeclaredField("sSystemFontMap");
                staticField.setAccessible(true);
                staticField.set(null, newMap);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } else {
            try {
                final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName);
                staticField.setAccessible(true);
                staticField.set(null, newTypeface);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } 
        }
    }

} 


在Application类中的用法:

public final class Application extends android.app.Application {
    @Override 
    public void onCreate() { 
        super.onCreate(); 
        FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
        FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
        FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
        FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
    } 
} 


设置一种样式来强制字体字体应用程序广泛使用(基于lovefish):

棒棒糖之前:

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:typeface">monospace</item>
   </style>
</resources>


<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:textAppearance">@style/CustomTextAppearance</item>
   </style>

   <style name="CustomTextAppearance">
       <item name="android:typeface">monospace</item>
   </style>
</resources>


选项2:在需要自定义字体的每个View子类化,即。 ListView,EditTextView,Button等(Palani的答案):

public class CustomFontView extends TextView {

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

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

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

private void init() { 
    if (!isInEditMode()) {
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
        setTypeface(tf);
    } 
} 


方法3:实现遍历当前屏幕视图层次结构的View Crawler:

版本1(汤姆的答案):

public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{ 
    if (mContainer == null || mFont == null) return;

    final int mCount = mContainer.getChildCount();

    // Loop through all of the children. 
    for (int i = 0; i < mCount; ++i)
    { 
        final View mChild = mContainer.getChildAt(i);
        if (mChild instanceof TextView)
        { 
            // Set the font if it is a TextView. 
            ((TextView) mChild).setTypeface(mFont);
        } 
        else if (mChild instanceof ViewGroup)
        { 
            // Recursively attempt another ViewGroup. 
            setAppFont((ViewGroup) mChild, mFont);
        } 
        else if (reflect)
        { 
            try { 
                Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
                mSetTypeface.invoke(mChild, mFont); 
            } catch (Exception e) { /* Do something... */ }
        } 
    } 
} 


用法:

final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf"));


变体2:https://coderwall.com/p/qxxmaa/android-use-a-custom-font-font-everywhere。

方法4:使用称为书法的第三方函数库。

我个人建议使用Option#4,因为它可以省去很多麻烦。

评论


在Option#1中,newMap.put()中的“ sans-serif”和样式中的等宽字符是什么意思?!我想使用一种名为barana.ttf的自定义字体。

–.jacky博士
18-2-15在6:27



在选项1中,第一个代码段不适用于API级别22(Android 5.1.1)。但是其他代码部分可以。如果这样的话,确切的含义是什么?

–user1510006
18/12/25在19:03

#5 楼

我想改善weston对API 21 Android 5.0的回答。

原因

在API 21下,大多数文本样式都包括fontFamily设置,例如:

<style name="TextAppearance.Material">
     <item name="fontFamily">@string/font_family_body_1_material</item>
</style>


使用默认的Roboto Regular字体:

<string name="font_family_body_1_material">sans-serif</string>


原始答案无法应用等宽字体,因为android:fontFamily对android:typeface属性(参考)具有更高的优先级。
使用Theme.Holo。*是有效的解决方法,因为其中没有android:fontFamily设置。

解决方案

由于Android 5.0将系统字体置于静态状态变量Typeface.sSystemFontMap(参考),我们可以使用相同的反射技术来替换它:

protected static void replaceFont(String staticTypefaceFieldName,
        final Typeface newTypeface) {
    if (isVersionGreaterOrEqualToLollipop()) {
        Map<String, Typeface> newMap = new HashMap<String, Typeface>();
        newMap.put("sans-serif", newTypeface);
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField("sSystemFontMap");
            staticField.setAccessible(true);
            staticField.set(null, newMap);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    } else {
        try {
            final Field staticField = Typeface.class
                    .getDeclaredField(staticTypefaceFieldName);
            staticField.setAccessible(true);
            staticField.set(null, newTypeface);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}


评论


L的一个不错的解决方法。但是,我想知道为什么这对于我的Buttons和Tool Bar标题似乎不起作用。我重写MainApplication中的默认字体,如下所示:FontsOverride.setDefaultFont(this,“ DEFAULT”,“ MyFontAsset.ttf”);。我正在使用Nexus 5,v5.1.1

– kip2
2015年6月8日在13:08



嘿,谢谢。这非常有用,只有一件事:在Android 6(API 22)上不起作用。然后将代码更改为:Build.VERSION.SDK_INT == 21-就是在API 21中,我在Nexus上使用API​​ 22测试

–赛义德
2015年10月6日13:30



仍然无法在Nexus 9中使用此方法设置自定义字体

–拉胡尔·阿帕德(Rahul Upadhyay)
2015年10月13日在7:04

任何有问题的人都不能在5.1+上工作。不要在您的values-v21样式中覆盖字体。

–穆罕默德·巴巴尔(Muhammad Babar)
16-2-19在10:13

@MuhammadBabar谢谢您的解决方案使我开心

– M. Yogeshwaran
16-10-7在11:30

#6 楼

它非常简单...
1.下载并将自定义字体放入资源中。然后编写一个单独的类用于文本视图,如下所示:在这里我使用了futura字体

public class CusFntTextView extends TextView {

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

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

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

private void init() {
    if (!isInEditMode()) {
        Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
        setTypeface(tf);
    }
}


}

,然后在xml中执行以下操作:

 <com.packagename.CusFntTextView
        android:id="@+id/tvtitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"         
        android:text="Hi Android"           
        android:textAppearance="?android:attr/textAppearanceLarge"
      />


评论


是的,这是可行的:)但是,如果我想对其他其余视图/小部件应用相同的字体怎么办?我是否还需要为所有其他视图(包括对话框/吐司/操作栏)编写单独的类?

– Narendra Singh
15年9月3日在18:25

是的,对于此解决方案,您需要为每个视图编写单独的类。

– Saad Bilal
16年8月20日在6:05

#7 楼

我也建议扩展TextView和其他控件,但最好考虑在构造中设置字体。

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

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

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

protected void init() {
    setTypeface(Typeface.createFromAsset(getContext().getAssets(), AppConst.FONT));
}


评论


在4.0之前的平台上执行此操作时要小心-由于Android中的错误,这会泄漏大量资源:code.google.com/p/android/issues/detail?id=9904

– Ryan M
13年6月20日在21:52

我们如何恢复为默认值。我正在做这样的事情:if(configShared.getString(“ storeId”,AppCredentials.DEFAULT_STORE_ID).equals(“ 2”)){final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName); staticField.setAccessible(true); staticField.set(null,newTypeface); } else {final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName); staticField.setAccessible(true); staticField.set(null,null); }

–杀手
16年2月15日在15:51

#8 楼

我想改善weston和Roger Huang对于超过21个主题为“ Theme.AppCompat”的Android棒棒糖的回答。

在Android 4.4以下

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:typeface">monospace</item>
   </style>
</resources>


Over(等于)API 5.0

<resources>
    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    </style>

   <!-- Application theme. -->
   <style name="AppTheme" parent="AppBaseTheme">
       <item name="android:textAppearance">@style/CustomTextAppearance</item>
   </style>

   <style name="CustomTextAppearance">
       <item name="android:typeface">monospace</item>
   </style>
</resources>


FontsOverride util文件与weston的答案相同。
我已经在以下手机中进行了测试:

Nexus 5(android 5.1主Android系统)

ZTE V5(android 5.1 CM12.1)

XIAOMI note(android 4.4 MIUI6)

HUAWEI C8850(android 2.3.5 UNKNOWN)

#9 楼

可以在以下网址找到一个出色的解决方案:https://coderwall.com/p/qxxmaa/android-use-a-custom-font-font-everywhere。

只需从BaseActivity扩展活动并编写这些方法即可。另外,您还应该按照以下说明更好地缓存字体:https://stackoverflow.com/a/16902532/2914140。经过研究后,我编写了适用于Samsung Galaxy Tab A的代码( Android 5.0)。使用了weston和Roger Huang以及https://stackoverflow.com/a/33236102/2914140的代码。在联想TAB 2 A10-70L上也进行了测试,但无法正常工作。
我在此处插入了字体'Comic Sans',以查看不同之处。

import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class FontsOverride {
    private static final int BOLD = 1;
    private static final int BOLD_ITALIC = 2;
    private static final int ITALIC = 3;
    private static final int LIGHT = 4;
    private static final int CONDENSED = 5;
    private static final int THIN = 6;
    private static final int MEDIUM = 7;
    private static final int REGULAR = 8;

    private Context context;

    public FontsOverride(Context context) {
        this.context = context;
    }

    public void loadFonts() {
        Map<String, Typeface> fontsMap = new HashMap<>();
        fontsMap.put("sans-serif", getTypeface("comic.ttf", REGULAR));
        fontsMap.put("sans-serif-bold", getTypeface("comic.ttf", BOLD));
        fontsMap.put("sans-serif-italic", getTypeface("comic.ttf", ITALIC));
        fontsMap.put("sans-serif-light", getTypeface("comic.ttf", LIGHT));
        fontsMap.put("sans-serif-condensed", getTypeface("comic.ttf", CONDENSED));
        fontsMap.put("sans-serif-thin", getTypeface("comic.ttf", THIN));
        fontsMap.put("sans-serif-medium", getTypeface("comic.ttf", MEDIUM));
        overrideFonts(fontsMap);
    }

    private void overrideFonts(Map<String, Typeface> typefaces) {
        if (Build.VERSION.SDK_INT == 21) {
            try {
                final Field field = Typeface.class.getDeclaredField("sSystemFontMap");
                field.setAccessible(true);
                Map<String, Typeface> oldFonts = (Map<String, Typeface>) field.get(null);
                if (oldFonts != null) {
                    oldFonts.putAll(typefaces);
                } else {
                    oldFonts = typefaces;
                }
                field.set(null, oldFonts);
                field.setAccessible(false);
            } catch (Exception e) {
                Log.e("TypefaceUtil", "Cannot set custom fonts");
            }
        } else {
            try {
                for (Map.Entry<String, Typeface> entry : typefaces.entrySet()) {
                    final Field staticField = Typeface.class.getDeclaredField(entry.getKey());
                    staticField.setAccessible(true);
                    staticField.set(null, entry.getValue());
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    private Typeface getTypeface(String fontFileName, int fontType) {
        final Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/" + fontFileName);
        return Typeface.create(tf, fontType);
    }
}


要在整个应用程序中运行代码,应在类似于Application的类中编写以下内容:

    new FontsOverride(this).loadFonts();


在“资产”中创建文件夹“字体”,然后将所需的字体放在此处。在这里可以找到一个简单的说明:https://stackoverflow.com/a/31697103/2914140。

Lenovo设备还错误地获取了字体的值。在大多数情况下,它返回Typeface.NORMAL,有时返回null。即使TextView为粗体(采用xml文件格式)。参见此处:TextView isBold始终返回NORMAL。这样,屏幕上的文本始终使用常规字体,而不是粗体或斜体。所以我认为这是生产者的错误。

评论


我研究了android源代码,您的答案是最好的。它可以代替薄,中,轻或其他任何东西。非常感谢!

–momt99
17年8月3日,9:44

#10 楼


为Xamarin.Android工作:

类:

 public class FontsOverride
{
    public static void SetDefaultFont(Context context, string staticTypefaceFieldName, string fontAssetName)
    {
        Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName);
        ReplaceFont(staticTypefaceFieldName, regular);
    }

    protected static void ReplaceFont(string staticTypefaceFieldName, Typeface newTypeface)
    {
        try
        {
            Field staticField = ((Java.Lang.Object)(newTypeface)).Class.GetDeclaredField(staticTypefaceFieldName);
            staticField.Accessible = true;
            staticField.Set(null, newTypeface);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}
 


应用程序实现:

 namespace SomeAndroidApplication
{
    [Application]
    public class App : Application
    {
        public App()
        {

        }

        public App(IntPtr handle, JniHandleOwnership transfer)
            : base(handle, transfer)
        {

        }

        public override void OnCreate()
        {
            base.OnCreate();

            FontsOverride.SetDefaultFont(this, "MONOSPACE", "fonts/Roboto-Light.ttf");
        }
    }
}
 


样式:

 <style name="Theme.Storehouse" parent="Theme.Sherlock">
    <item name="android:typeface">monospace</item>
</style>
 


#11 楼

从Android O开始,现在可以直接从XML进行定义,并且我的bug已经关闭!

有关详细信息,请参见此处。

TL; DR:

首先,您必须将字体添加到项目中。

其次,添加字体家族,例如:

<?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/lobster_regular" />
    <font
        android:fontStyle="italic"
        android:fontWeight="400"
        android:font="@font/lobster_italic" />
</font-family>


最后,您可以在布局或样式中使用字体:

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

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


享受!

评论


谢谢。我们应该使用Android Studio 2.4来添加字体文件夹。

–光子点
17年4月21日在7:48

实际上,我只需要将其应用到我的样式中,即可通过应用程序进行应用。但有些(以编程方式添加的控件将需要通过Java代码应用)

– SolidSnake
17年8月28日在3:30

#12 楼

您可以为每个布局一个一个地设置自定义字体,只需通过传递其根视图就可以从每个布局中调用一个函数。首先,创建一种用于访问字体对象的singelton方法,如下所示:

 public class Font {
    private static Font font;
    public Typeface ROBO_LIGHT;

    private Font() {

    }

    public static Font getInstance(Context context) {
        if (font == null) {
            font = new Font();
            font.init(context);
        }
        return font;

    }

    public void init(Context context) {

        ROBO_LIGHT = Typeface.createFromAsset(context.getAssets(),
                "Roboto-Light.ttf");
    }

}


您可以在上面的类中定义不同的字体,现在定义一个将应用字体的字体帮助器类:

   public class FontHelper {

    private static Font font;

    public static void applyFont(View parentView, Context context) {

        font = Font.getInstance(context);

        apply((ViewGroup)parentView);

    }

    private static void apply(ViewGroup parentView) {
        for (int i = 0; i < parentView.getChildCount(); i++) {

            View view = parentView.getChildAt(i);

//You can add any view element here on which you want to apply font 

            if (view instanceof EditText) {

                ((EditText) view).setTypeface(font.ROBO_LIGHT);

            }
            if (view instanceof TextView) {

                ((TextView) view).setTypeface(font.ROBO_LIGHT);

            }

            else if (view instanceof ViewGroup
                    && ((ViewGroup) view).getChildCount() > 0) {
                apply((ViewGroup) view);
            }

        }

    }

}


在上面的代码中,我正在应用如果仅在textView和EditText上使用字体,则可以类似地将字体应用于其他视图元素。只需将根View组的ID传递给上述apply font方法。例如,您的布局是:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/mainParent"
    tools:context="${relativePackage}.${activityClass}" >

    <RelativeLayout
        android:id="@+id/mainContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/homeFooter"
        android:layout_below="@+id/edit" >

        <ImageView
            android:id="@+id/PreviewImg"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/abc_list_longpressed_holo"
            android:visibility="gone" />

        <RelativeLayout
            android:id="@+id/visibilityLayer"
            android:layout_width="match_parent"
            android:layout_height="fill_parent" >

            <ImageView
                android:id="@+id/UseCamera"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:src="@drawable/camera" />

            <TextView
                android:id="@+id/tvOR"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/UseCamera"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="20dp"
                android:text="OR"
                android:textSize="30dp" />

            <TextView
                android:id="@+id/tvAND"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="20dp"
                android:text="OR"
                android:textSize="30dp" />

</RelativeLayout>


在上述布局中,根父ID为“ Main Parent”,现在可以应用字体

public class MainActivity extends BaseFragmentActivity {

    private EditText etName;
    private EditText etPassword;
    private TextView tvTitle;
    public static boolean isHome = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       Font font=Font.getInstance(getApplicationContext());
        FontHelper.applyFont(findViewById(R.id.mainParent),          getApplicationContext());
   }    
}


干杯:)

评论


很好..没有更多相同的字体可以重新创建,所有字段仅使用一种字体。 :)

– Arfan Mirza
15年3月13日在10:30

#13 楼

我建议扩展TextView,并始终在XML布局中或需要TextView的任何地方使用自定义TextView。在自定义TextView中,覆盖setTypeface

@Override
public void setTypeface(Typeface tf, int style) {
    //to handle bold, you could also handle italic or other styles here as well
    if (style == 1){
        tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans700.otf");
    }else{
        tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans500.otf");
    }
    super.setTypeface(tf, 0);
}


#14 楼

Tom的解决方案效果很好,但仅适用于TextView和EditText。

如果您想涵盖大多数视图(RadioGroup,TextView,Checkbox ...),我创建了一个方法:

protected void changeChildrenFont(ViewGroup v, Typeface font){
    for(int i = 0; i < v.getChildCount(); i++){

        // For the ViewGroup, we'll have to use recursivity
        if(v.getChildAt(i) instanceof ViewGroup){
            changeChildrenFont((ViewGroup) v.getChildAt(i), font);
        }
        else{
            try {
                Object[] nullArgs = null;
                //Test wether setTypeface and getTypeface methods exists
                Method methodTypeFace = v.getChildAt(i).getClass().getMethod("setTypeface", new Class[] {Typeface.class, Integer.TYPE});
                //With getTypefaca we'll get back the style (Bold, Italic...) set in XML
                Method methodGetTypeFace = v.getChildAt(i).getClass().getMethod("getTypeface", new Class[] {});
                Typeface typeFace = ((Typeface)methodGetTypeFace.invoke(v.getChildAt(i), nullArgs));
                //Invoke the method and apply the new font with the defined style to the view if the method exists (textview,...)
                methodTypeFace.invoke(v.getChildAt(i), new Object[] {font, typeFace == null ? 0 : typeFace.getStyle()});
            }
            //Will catch the view with no such methods (listview...)
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


此方法将获取XML中的视图集样式(粗体,斜体...),并将其应用(如果存在)。

对于ListView,我总是创建一个适配器,并在getView中设置字体。

#15 楼

我编写了一个将字体分配给当前视图层次结构中的视图的类,并基于当前的字体属性(粗体,普通,如果需要,您可以添加其他样式):

public final class TypefaceAssigner {

public final Typeface DEFAULT;
public final Typeface DEFAULT_BOLD;

@Inject
public TypefaceAssigner(AssetManager assetManager) {
    DEFAULT = Typeface.createFromAsset(assetManager, "TradeGothicLTCom.ttf");
    DEFAULT_BOLD = Typeface.createFromAsset(assetManager, "TradeGothicLTCom-Bd2.ttf");
}

public void assignTypeface(View v) {
    if (v instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) v).getChildCount(); i++) {
            View view = ((ViewGroup) v).getChildAt(i);
            if (view instanceof ViewGroup) {
                setTypeface(view);
            } else {
                setTypeface(view);
            }
        }
    } else {
        setTypeface(v);
    }
}

private void setTypeface(View view) {
    if (view instanceof TextView) {
        TextView textView = (TextView) view;
        Typeface typeface = textView.getTypeface();
        if (typeface != null && typeface.isBold()) {
            textView.setTypeface(DEFAULT_BOLD);
        } else {
            textView.setTypeface(DEFAULT);
        }
    }
}
}

<现在,在onViewCreated或onCreateView的所有片段,onCreate的所有活动以及getView或newView的所有视图适配器中,只需调用:

typefaceAssigner.assignTypeface(view);


#16 楼

在具有build.gradle 3.0.0及更高版本的api 26中,您可以在res中创建字体目录
,并以您的样式使用此行

<item name="android:fontFamily">@font/your_font</item>


进行更改build.gradle在您的build.gradle依赖项中使用它

classpath 'com.android.tools.build:gradle:3.0.0'


评论


以及如何将字体插入项目中?

–azerafati
18年1月17日在13:26

@azerafati将您的字体复制到res / font

–穆罕默德·侯赛因·海达里(Mohammad Hosein Heidari)
18年1月20日在11:23

是的,坦克斯我已经知道了但是仅此一项并不能为整个应用程序设置字体。有什么线索吗?

–azerafati
18年1月20日在13:47

#17 楼

最终,Google意识到了这个问题的严重性(将自定义字体应用于UI组件),他们为此设计了一个干净的解决方案。

首先,您需要更新以支持库26+(您可能还需要以更新gradle {4.0 +}(Android Studio)),则可以创建一个名为font的新资源文件夹。在此文件夹中,您可以放置​​字体资源(.tff,...)。
然后您需要覆盖默认应用程序,并将其强制使用自定义字体:)

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:fontFamily">@font/my_custom_font</item>
</style>


注意:如果要支持API大于16的设备,则必须使用应用程序名称空间而不是android!

#18 楼

我还想改善weston对API 21 Android 5.0的回答。

使用DEFAULT字体时,我在Samsung s5上遇到了同样的问题。 (使用其他字体,它可以正常工作)

我设法通过在XML文件中为每个Textview或Button设置字体(例如“ sans”)来使其正常工作

<TextView
android:layout_width="match_parent"
android:layout_height="39dp"
android:textColor="@color/abs__background_holo_light"
android:textSize="12sp"
android:gravity="bottom|center"
android:typeface="sans" />


,在MyApplication类中:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
    TypefaceUtil.overrideFont(getApplicationContext(), "SANS_SERIF",
    "fonts/my_font.ttf");
    }
}


希望对您有所帮助。

#19 楼

此解决方案在某些情况下无法正常工作。
所以我将其扩展:

FontsReplacer.java

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        FontsReplacer.replaceFonts(this);
        super.onCreate();
    }

}


https:/ /gist.github.com/orwir/6df839e3527647adc2d56bfadfaad805

#20 楼

书法效果很好,但是不适合我,因为它不支持字体家族的不同粗细(粗体,斜体等)。

所以我尝试了Fontain,它可以让您定义自定义视图并应用自定义字体系列。

要使用Fontain,应将以下内容添加到应用程序模块build.gradle:

compile 'com.scopely:fontain:1.0.0'


然后,而不是使用常规TextView,应该使用FontTextView

具有大写和粗体内容的FontTextView示例:

 <com.scopely.fontain.views.FontTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/black"
            android:textColor="@android:color/white"
            android:textSize="11dp"
            android:gravity="center"
            android:id="@+id/tv1"
            app:font_family="myCustomFont"
            app:caps_mode="characters"
            app:font_weight="BOLD"/>


#21 楼

package com.theeasylearn.demo.designdemo;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

public class MyButton extends TextView {

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

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

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

    private void init() {

            Typeface tf =
                    Typeface.createFromAsset(
                            getContext().getAssets(), "angelina.TTF");
            setTypeface(tf);

    }

}


评论


不是一个完美的解决方案。使用此解决方案将需要自定义解决方法以访问默认的Android TextView

– blueware
17年7月9日在7:07

#22 楼

要更改TextViews的默认字体系列,请在应用程序主题中覆盖textViewStyle。

要在fontFamily中使用自定义字体,请使用支持库中的字体资源。

该功能已在Android 26中添加,但通过supportlib向后移植到旧版本。

https://developer.android.com/guide/topics/resources/font-resource .html
https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html#using-support-lib

#23 楼

自Android Oreo及其支持库(26.0.0)发行以来,您可以轻松实现此目的。请在另一个问题中参考此答案。

基本上,您的最终样式将如下所示:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
   <item name="fontFamily">@font/your_font</item> <!-- target android sdk versions < 26 and > 14 -->
</style>


#24 楼

我发现书法3库和coderwall帖子的混合是我的最终结果。

#25 楼

是的,可以将字体设置为整个应用程序。

最简单的方法是将所需字体与应用程序打包在一起。

为此,只需在项目根目录中创建一个资产/文件夹,然后将字体(以
TrueType或TTF形式)放在资产中。

例如,您可能创建资产/字体/并将TTF文件放入其中。

public class FontSampler extends Activity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView tv=(TextView)findViewById(R.id.custom);

Typeface face=Typeface.createFromAsset(getAssets(), "fonts/HandmadeTypewriter.ttf");
tv.setTypeface(face);
}
}