是否可以为整个应用程序设置自定义字体?

我需要使用某些字体为我的整个应用程序。我有。ttf文件相同。 是否有可能将此设置为默认字体,在应用程序启动,然后在应用程序的其他地方使用它?当设置,我如何使用它在我的布局xml ?< / p >

160458 次浏览

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

实现这一点的最简单方法是将所需的字体打包到应用程序中。

要做到这一点,只需在项目根目录中创建一个资产/文件夹,并将您的字体(放在 TrueType,或TTF表单)。< / p >

例如,你可以创建资产/字体并将你的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);
}
}

虽然这并不适用于整个应用程序,但它适用于一个活动,并且可以重用于任何其他活动。我已经更新了我的代码,感谢@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,并始终使用您的自定义TextView在您的XML布局或任何地方,你需要一个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);
}

我还建议扩展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));
}

是的,还有反思。这工作(基于这个答案):

(注意:这是一种变通方法,因为不支持自定义字体,所以如果你想改变这种情况,请给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>

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

如果你想覆盖大部分的视图(RadioGroup, TextView,复选框…),我创建了一个方法:

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中设置字体。

很简单… 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"
/>

我想改进韦斯顿的API 21 Android 5.0的答案。

导致

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

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

它应用默认的Roboto常规字体:

<string name="font_family_body_1_material">sans-serif</string>
原来的答案不能应用monospace字体,因为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();
}
}
}

为萨玛林工作。Android: < / p >

类:

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>

您可以为每个布局逐个设置自定义字体,只需通过传递根视图从每个布局调用一个函数即可。首先,创建一个像这样访问字体对象的单例方法

 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上应用字体,你也可以在其他视图元素上应用字体。你只需要把根视图组的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());
}
}

欢呼:)

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

我的三星s5在使用默认字体时也遇到了同样的问题。(与其他字体的工作很好)

我设法使它工作通过设置字体(“sans”为例)在XML文件,为每个Textview或按钮

<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");
}
}

希望能有所帮助。

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

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);

我想改善韦斯顿罗杰·黄的答案超过API 21 Android棒棒糖主题“主题。AppCompat”。

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>

超过(等于)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文件与韦斯顿的答案相同。 我在这些手机上进行了测试:

Nexus 5(android 5.1主系统)

中兴通讯V5(android 5.1 CM12.1)

小米note(android 4.4 MIUI6)

华为C8850(android 2.3.5未知)

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

简单地从BaseActivity扩展活动并编写这些方法。此外,你应该更好地缓存字体,如这里所述:https://stackoverflow.com/a/16902532/2914140


经过一些研究后,我写了在三星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();

在“assets”里面创建一个文件夹“fonts”,把需要的字体放在那里。这里可以找到一个简单的指令:https://stackoverflow.com/a/31697103/2914140

联想设备还错误地获取了字体的值。在大多数情况下,它返回字体。NORMAL,有时为空。即使TextView是粗体(在xml文件布局)。看这里:TextView isBold总是返回NORMAL。这样,屏幕上的文本总是使用常规字体,而不是粗体或斜体。所以我认为这是制作人的错误。

在android:书法中有一个很棒的自定义字体库

这里有一个如何使用它的示例。

在Gradle中,你需要将这一行放入应用程序的构建中。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()
);
}
}

在activity类中将这个方法放在onCreate之前:

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

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

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

它将改变整个活动,以您的字体!既简单又干净!

总而言之:

选项1:使用反射来应用字体(结合韦斯顿 &罗杰·黄的回答):

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();
}
}
}


}

应用类使用:

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):

Pre-Lollipop:

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


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

棒棒糖(API 21):

<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>

Option2:子类每个视图,你需要自定义字体,即。ListView, EditTextView, Button等(的答案):

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);
}
}

实现一个视图爬虫,遍历当前屏幕的视图层次结构:

变体#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-everywhere

使用名为书法的第三方Lib。

就我个人而言,我会推荐选项4,因为它省去了很多麻烦。

solution在某些情况下不正确工作 所以我扩展它:

FontsReplacer.java

public class MyApplication extends Application {


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


}

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

书法工作得很好,但它不适合我,因为它不支持字体族的不同权重(粗体,斜体等)。

所以我尝试了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"/>
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 O开始,现在可以直接从XML和我的bug现在关闭了!定义

详情见这里

TL;博士:

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

其次,添加一个字体系列,如下所示:

<?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>

享受吧!

在API 26与构建。Gradle 3.0.0及更高版本可以在res中创建字体目录 在你的样式中使用这一行

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

对于变更构建。Gradle在你的构建中使用这个。gradle dependecies

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

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

首先,你需要更新到支持库26+(你可能还需要更新你的gradle{4.0+}, android studio),然后你可以创建一个新的资源文件夹称为字体。在这个文件夹中,您可以放置您的字体资源(.tff,…) 然后你需要覆盖默认的应用程序,并强制你的自定义字体:)

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

注意:如果你想要支持API超过16的设备,你必须使用app命名空间而不是android!

为了改变textview的默认字体家族,重写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 < / p >

由于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>

我发现书法3库coderwall的文章的混合物是我的最终结果。