Android:想要为整个应用程序而不是运行时设置自定义字体

Posted

技术标签:

【中文标题】Android:想要为整个应用程序而不是运行时设置自定义字体【英文标题】:Android: Want to set custom fonts for whole application not runtime 【发布时间】:2011-05-22 16:08:04 【问题描述】:

是否可以在应用程序的每个控件中设置任何自定义字体?不一定是运行时? (即,如果可能,从 xml 或 JAVA 文件中的整个应用程序只使用一次)

我可以通过这段代码为一个控件设置字体。

public static void setFont(TextView textView) 
    Typeface tf = Typeface.createFromAsset(textView.getContext()
            .getAssets(), "fonts/BPreplay.otf");

    textView.setTypeface(tf);


这段代码的问题是每个控件都应该调用它。我想调用这个或任何类似的方法一次,或者如果可能的话在 xml 中设置属性。有可能吗?

【问题讨论】:

也许您可以通过扩展 TextView 并在构造函数中设置字体来编写自定义控件,然后您可以在整个应用程序中使用此控件代替您的 textview。为了节省内存,你可以使用静态字体类型来防止加载资源。 @Varun :这个想法可以节省我的时间,但是我必须设置每个控件,并且为每个控件编写自定义控件将比设置字体运行时更长,你怎么看? (但是 +1 用于编写自定义控件) 您可能只想编写一个扩展 textView 的自定义控件,唯一的修改是设置字体。通过在布局文件中使用 cusotm 控件,您不必每次都为每个 textview 手动执行此操作,并且您仍然可以确保您使用的是您想要的字体。 写一个自定义的VIEW而不是分别写一个custom text viewcustom button view怎么样?我的要求是针对每个控件,文本视图只是一个示例。对不起,我忘了提.. :-( 看看 satckoverflow 问题***.com/questions/2711858/… 它对你有帮助。 【参考方案1】:

编辑:已经有一段时间了,我想添加我认为最好的方法,并且通过 XML 来实现!

首先,您需要创建一个新类来覆盖您想要自定义的任何视图。 (例如,想要一个带有自定义字体的按钮?扩展 Button)。我们举个例子:

public class CustomButton extends Button 
    private final static int ROBOTO = 0;
    private final static int ROBOTO_CONDENSED = 1;

    public CustomButton(Context context) 
        super(context);
    

    public CustomButton(Context context, AttributeSet attrs) 
        super(context, attrs);
        parseAttributes(context, attrs); //I'll explain this method later
    

    public CustomButton(Context context, AttributeSet attrs, int defStyle) 
        super(context, attrs, defStyle);
        parseAttributes(context, attrs);
    

现在,如果您没有,请在res/values/attrs.xml 下添加一个 XML 文档,然后添加:

<resources>
    <!-- Define the values for the attribute -->
    <attr name="typeface" format="enum">
        <enum name="roboto" value="0"/>
        <enum name="robotoCondensed" value="1"/>
    </attr>

    <!-- Tell android that the class "CustomButton" can be styled, 
         and which attributes it supports -->
    <declare-styleable name="CustomButton">
        <attr name="typeface"/>
    </declare-styleable>
</resources>

好的,那么,让我们回到之前的 parseAttributes() 方法:

private void parseAttributes(Context context, AttributeSet attrs) 
    TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomButton);

    //The value 0 is a default, but shouldn't ever be used since the attr is an enum
    int typeface = values.getInt(R.styleable.CustomButton_typeface, 0);

    switch(typeface) 
        case ROBOTO: default:
            //You can instantiate your typeface anywhere, I would suggest as a 
            //singleton somewhere to avoid unnecessary copies
            setTypeface(roboto); 
            break;
        case ROBOTO_CONDENSED:
            setTypeface(robotoCondensed);
            break;
    

    values.recycle();

现在一切就绪。您可以为任何东西添加更多属性(您可以为字体样式添加另一个属性——粗体、斜体等),但现在让我们看看如何使用它:

<?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/com.yourpackage.name"
    android:layout_
    android:layout_
    android:orientation="vertical" >

    <com.yourpackage.name.CustomButton
        android:id="@+id/button"
        android:layout_
        android:layout_
        android:text="Click Me!"
        custom:typeface="roboto" />

</LinearLayout>

xmlns:custom 行实际上可以是任何东西,但约定如上所示。重要的是它是独一无二的,这就是使用包名称的原因。现在您只需为属性使用custom: 前缀,为android 属性使用android: 前缀。

最后一件事:如果您想在样式中使用它 (res/values/styles.xml),您应该添加 xmlns:custom 行。只需引用不带前缀的属性名称:

<style name="MyStyle>
    <item name="typeface">roboto</item>
</style>

                               (PREVIOUS ANSWER)

Using a custom typeface in Android

这应该会有所帮助。基本上,在 XML 中没有办法做到这一点,而且据我所知,没有更简单的方法可以在代码中做到这一点。您总是可以有一个 setLayoutFont() 方法,该方法创建一次字体,然后为每个字体运行 setTypeface()。每次将新项目添加到布局时,您只需更新它。如下所示:

public void setLayoutFont() 
    Typeface tf = Typeface.createFromAsset(
        getBaseContext().getAssets(), "fonts/BPreplay.otf");
    TextView tv1 = (TextView)findViewById(R.id.tv1);
    tv1.setTypeface(tf);

    TextView tv2 = (TextView)findViewById(R.id.tv2);
    tv2.setTypeface(tf);

    TextView tv3 = (TextView)findViewById(R.id.tv3);
    tv3.setTypeface(tf);

编辑:所以我开始自己实现类似的东西,而我最终是如何实现这样的功能的:

public static void setLayoutFont(Typeface tf, TextView...params) 
    for (TextView tv : params) 
        tv.setTypeface(tf);
    

然后,只需使用 onCreate() 中的此方法,并传递您要更新的所有 TextView:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
//find views by id...
setLayoutFont(tf, tv1, tv2, tv3, tv4, tv5);

编辑 9/5/12:

因此,由于这仍在获得意见和投票,我想添加一个更好、更完整的方法:

Typeface mFont = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
ViewGroup root = (ViewGroup)findViewById(R.id.myrootlayout);
setFont(root, mFont);

/*
 * Sets the font on all TextViews in the ViewGroup. Searches
 * recursively for all inner ViewGroups as well. Just add a
 * check for any other views you want to set as well (EditText,
 * etc.)
 */
public void setFont(ViewGroup group, Typeface font) 
    int count = group.getChildCount();
    View v;
    for(int i = 0; i < count; i++) 
        v = group.getChildAt(i);
        if(v instanceof TextView || v instanceof Button /*etc.*/)
            ((TextView)v).setTypeface(font);
        else if(v instanceof ViewGroup)
            setFont((ViewGroup)v, font);
    

如果您将布局的根传递给它,它将递归检查该布局中的 TextViewButton 视图(或您添加到该 if 语句的任何其他视图),并设置字体而无需指定他们的身份证。这当然是假设您要将字体设置为 every 视图。

【讨论】:

我看不出你的代码和我的代码有任何区别,除了我使用该方法作为整个应用程序的工厂方法并且你的代码似乎是为一个活动编写的。附言为只读 textView 添加一个对象只是为了更改字体真的很奇怪。题外话:Android 应该真正引入一种机制来从assets 文件夹中获取字体并包含在R 中,以便可以在设计时更改它) 我想实际上没有什么大的区别,除了你不会一遍又一遍地创建字体。 Varun 只使用静态字体的想法也可以做到这一点。 示例代码的最后一行是否应为 setLayoutFont(tf, tv1, tv2, tv3, tv4, tv5);而不是 setTypeface(tf, tv1, tv2, tv3, tv4, tv5);? 你不应该recycleTypedArray values吗? 如果使用 Gradle,自定义命名空间应为xmlns:custom="http://schemas.android.com/apk/res-auto"【参考方案2】:

通过 XML 有一种相当简单的方法可以做到这一点。您只需要创建自己的扩展 TextView 的小部件。

首先,在 res/values/attrs.xml 中创建一个文件,内容如下:

<resources>
    <declare-styleable name="TypefacedTextView">
        <attr name="typeface" format="string" />
    </declare-styleable>
</resources>

之后,创建您的自定义小部件:

package your.package.widget;

public class TypefacedTextView extends TextView 

    public TypefacedTextView(Context context, AttributeSet attrs) 
        super(context, attrs);

        //Typeface.createFromAsset doesn't work in the layout editor. Skipping...
        if (isInEditMode()) 
            return;
        

        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.TypefacedTextView);
        String fontName = styledAttrs.getString(R.styleable.TypefacedTextView_typeface);
        styledAttrs.recycle();

        if (fontName != null) 
            Typeface typeface = Typeface.createFromAsset(context.getAssets(), fontName);
            setTypeface(typeface);
        
    


如您所见,上面的代码将读取 assets/ 文件夹中的字体。对于此示例,我假设资产文件夹中有一个名为“custom.ttf”的文件。最后,使用 XML 中的小部件:

<your.package.widget.TypefacedTextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:your_namespace="http://schemas.android.com/apk/res/your.package"
    android:layout_
    android:layout_
    android:text="Custom fonts in XML are easy"
    android:textColor="#FFF"
    android:textSize="14dip"
    your_namespace:typeface="custom.ttf" />

注意:您将无法在 Eclipse 的布局编辑器中看到您的自定义字体。这就是我选择isInEditMode() 的原因。但是如果你运行你的应用程序,自定义字体就会像魅力一样发挥作用。

希望对你有帮助!

【讨论】:

这个我没试过,但是我通过扩展TextView类创建了一个自定义控件;在其中设置typeface 并像往常一样在布局中使用自定义控件,它对我有用……不过,上面那个很简单…… 我完全按照你说的做了。唯一的区别是我使这个组件可重用,因为问题询问如何通过 XML 执行此操作。确实有一种方法可以通过 XML 做到这一点,这就是这样做的方法:) 非常容易集成代码。这个对我有用。谢谢。 这应该是公认的答案。写的很好。谢谢! 太棒了,@DominikSuszczewicz!您能否分享代码以便我更新答案?【参考方案3】:

带有roboto字体的TextView示例:

attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="RobotoTextView">
    <attr name="typeface"/>
</declare-styleable>

<attr name="typeface" format="enum">
    <enum name="roboto_thin" value="0"/>
    <enum name="roboto_thin_italic" value="1"/>
    <enum name="roboto_light" value="2"/>
    <enum name="roboto_light_italic" value="3"/>
    <enum name="roboto_regular" value="4"/>
    <enum name="roboto_italic" value="5"/>
    <enum name="roboto_medium" value="6"/>
    <enum name="roboto_medium_italic" value="7"/>
    <enum name="roboto_bold" value="8"/>
    <enum name="roboto_bold_italic" value="9"/>
    <enum name="roboto_black" value="10"/>
    <enum name="roboto_black_italic" value="11"/>
    <enum name="roboto_condensed" value="12"/>
    <enum name="roboto_condensed_italic" value="13"/>
    <enum name="roboto_condensed_bold" value="14"/>
    <enum name="roboto_condensed_bold_italic" value="15"/>
</attr>

</resources>

RobotoTextView.java:

public class RobotoTextView extends TextView 

/*
 * Permissible values ​​for the "typeface" attribute.
 */
private final static int ROBOTO_THIN = 0;
private final static int ROBOTO_THIN_ITALIC = 1;
private final static int ROBOTO_LIGHT = 2;
private final static int ROBOTO_LIGHT_ITALIC = 3;
private final static int ROBOTO_REGULAR = 4;
private final static int ROBOTO_ITALIC = 5;
private final static int ROBOTO_MEDIUM = 6;
private final static int ROBOTO_MEDIUM_ITALIC = 7;
private final static int ROBOTO_BOLD = 8;
private final static int ROBOTO_BOLD_ITALIC = 9;
private final static int ROBOTO_BLACK = 10;
private final static int ROBOTO_BLACK_ITALIC = 11;
private final static int ROBOTO_CONDENSED = 12;
private final static int ROBOTO_CONDENSED_ITALIC = 13;
private final static int ROBOTO_CONDENSED_BOLD = 14;
private final static int ROBOTO_CONDENSED_BOLD_ITALIC = 15;
/**
 * List of created typefaces for later reused.
 */
private final static SparseArray<Typeface> mTypefaces = new SparseArray<Typeface>(16);

/**
 * Simple constructor to use when creating a view from code.
 *
 * @param context The Context the view is running in, through which it can
 *                access the current theme, resources, etc.
 */
public RobotoTextView(Context context) 
    super(context);


/**
 * Constructor that is called when inflating a view from XML. This is called
 * when a view is being constructed from an XML file, supplying attributes
 * that were specified in the XML file. This version uses a default style of
 * 0, so the only attribute values applied are those in the Context's Theme
 * and the given AttributeSet.
 * <p/>
 * <p/>
 * The method onFinishInflate() will be called after all children have been
 * added.
 *
 * @param context The Context the view is running in, through which it can
 *                access the current theme, resources, etc.
 * @param attrs   The attributes of the XML tag that is inflating the view.
 * @see #RobotoTextView(Context, AttributeSet, int)
 */
public RobotoTextView(Context context, AttributeSet attrs) 
    super(context, attrs);
    parseAttributes(context, attrs);


/**
 * Perform inflation from XML and apply a class-specific base style. This
 * constructor of View allows subclasses to use their own base style when
 * they are inflating.
 *
 * @param context  The Context the view is running in, through which it can
 *                 access the current theme, resources, etc.
 * @param attrs    The attributes of the XML tag that is inflating the view.
 * @param defStyle The default style to apply to this view. If 0, no style
 *                 will be applied (beyond what is included in the theme). This may
 *                 either be an attribute resource, whose value will be retrieved
 *                 from the current theme, or an explicit style resource.
 * @see #RobotoTextView(Context, AttributeSet)
 */
public RobotoTextView(Context context, AttributeSet attrs, int defStyle) 
    super(context, attrs, defStyle);
    parseAttributes(context, attrs);


/**
 * Parse the attributes.
 *
 * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
 * @param attrs   The attributes of the XML tag that is inflating the view.
 */
private void parseAttributes(Context context, AttributeSet attrs) 
    TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.RobotoTextView);

    int typefaceValue = values.getInt(R.styleable.RobotoTextView_typeface, 0);
    values.recycle();

    setTypeface(obtaintTypeface(context, typefaceValue));


/**
 * Obtain typeface.
 *
 * @param context       The Context the view is running in, through which it can
 *                      access the current theme, resources, etc.
 * @param typefaceValue values ​​for the "typeface" attribute
 * @return Roboto @link Typeface
 * @throws IllegalArgumentException if unknown `typeface` attribute value.
 */
private Typeface obtaintTypeface(Context context, int typefaceValue) throws IllegalArgumentException 
    Typeface typeface = mTypefaces.get(typefaceValue);
    if (typeface == null) 
        typeface = createTypeface(context, typefaceValue);
        mTypefaces.put(typefaceValue, typeface);
    
    return typeface;


/**
 * Create typeface from assets.
 *
 * @param context       The Context the view is running in, through which it can
 *                      access the current theme, resources, etc.
 * @param typefaceValue values ​​for the "typeface" attribute
 * @return Roboto @link Typeface
 * @throws IllegalArgumentException if unknown `typeface` attribute value.
 */
private Typeface createTypeface(Context context, int typefaceValue) throws IllegalArgumentException 
    Typeface typeface;
    switch (typefaceValue) 
        case ROBOTO_THIN:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Thin.ttf");
            break;
        case ROBOTO_THIN_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-ThinItalic.ttf");
            break;
        case ROBOTO_LIGHT:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Light.ttf");
            break;
        case ROBOTO_LIGHT_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-LightItalic.ttf");
            break;
        case ROBOTO_REGULAR:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf");
            break;
        case ROBOTO_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Italic.ttf");
            break;
        case ROBOTO_MEDIUM:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Medium.ttf");
            break;
        case ROBOTO_MEDIUM_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-MediumItalic.ttf");
            break;
        case ROBOTO_BOLD:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Bold.ttf");
            break;
        case ROBOTO_BOLD_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldItalic.ttf");
            break;
        case ROBOTO_BLACK:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Black.ttf");
            break;
        case ROBOTO_BLACK_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BlackItalic.ttf");
            break;
        case ROBOTO_CONDENSED:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Condensed.ttf");
            break;
        case ROBOTO_CONDENSED_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-CondensedItalic.ttf");
            break;
        case ROBOTO_CONDENSED_BOLD:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensed.ttf");
            break;
        case ROBOTO_CONDENSED_BOLD_ITALIC:
            typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensedItalic.ttf");
            break;
        default:
            throw new IllegalArgumentException("Unknown `typeface` attribute value " + typefaceValue);
    
    return typeface;



使用示例:

<your.package.widget.RobotoTextView
                android:layout_
                android:layout_
                app:typeface="roboto_thin"
                android:textSize="22sp"
                android:text="Roboto Thin"/>

资源: Roboto & Noto fonts

【讨论】:

有一种方法可以使用此解决方案,但无需修复 java 类中的字体 ID?也许从枚举属性中读取这些最终字段.. private final static int ROBOTO_THIN = 0;私有最终静态 int ROBOTO_THIN_ITALIC = 1;私有最终静态 int ROBOTO_LIGHT = 2; ...【参考方案4】:

为时已晚,但我的它可以帮助其他人 我创建了 CustomTextView,它有一个名为 typeFace 的属性,它可以解决没有缓存的字体加载的内存泄漏问题

首先是Fonts类,它只从资源中加载字体一次

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

import java.util.Hashtable;

/**
 * Created by tonyhaddad on 7/19/15.
 */
public class Fonts 
    private Context context;

    public Fonts(Context context) 
        this.context = context;
    
    private static Hashtable<String, Typeface> sTypeFaces = new Hashtable<String, Typeface>(
            4);
    public static Typeface getTypeFace(Context context, String fileName) 
        Typeface tempTypeface = sTypeFaces.get(fileName);

        if (tempTypeface == null) 
            String fontPath=null;
            if(fileName=="metabold")
                fontPath ="fonts/Meta-Bold.ttf";

            else if(fileName=="metanormal")
                fontPath="fonts/Meta-Normal.ttf";
            else if(fileName=="gsligh")
                fontPath="fonts/gesslight.ttf";
            else if(fileName=="bold")
                fontPath="fonts/Lato-Bold.ttf";
            else if(fileName=="rcr")
                fontPath="fonts/RobotoCondensed-Regular.ttf";

            else if(fileName=="mpr")
                fontPath="fonts/MyriadPro-Regular.otf";
            else if(fileName=="rr")
                fontPath="fonts/Roboto-Regular.ttf";

            tempTypeface = Typeface.createFromAsset(context.getAssets(), fontPath);
            sTypeFaces.put(fileName, tempTypeface);
        

        return tempTypeface;
    

那么你需要在attrs.xml中添加一个自定义属性添加这个

<declare-styleable name="CustomFontTextView">
        <attr name="typeFace" format="string" />

    </declare-styleable>

然后自定义类

 package package_name;

/**
 * Created by tonyhaddad on 8/26/15.
 */

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

import package_name.R;

public class CustomFontTextView extends TextView 

    String typeFace;


    public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) 
        super(context, attrs, defStyle);
        if (isInEditMode()) 
            return;
        
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomFontTextView,
                0, 0);
        try 
            typeFace = a.getString(0);
         finally 
            a.recycle();
        

        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        
        init();
    

    public CustomFontTextView(Context context, AttributeSet attrs) 
        super(context, attrs);
        if (isInEditMode()) 
            return;
        
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.CustomFontTextView,
                0, 0);
        try 
            typeFace = a.getString(0);
         finally 
            a.recycle();
        

        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        

        init();
    

    public CustomFontTextView(Context context) 
        super(context);



        if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
        
            Typeface tf = Fonts.getTypeFace(context, typeFace);
            setTypeface(tf);
        
        init();
    


    private void init() 

    

    public String getTypeFace() 
        return typeFace;
    

    public void setTypeFace(String typeFace) 
        this.typeFace = typeFace;
        invalidate();
        requestLayout();
    

最后添加文本视图

  <package_name.CustomFontTextView
            xmlns:custom="http://schemas.android.com/apk/res-auto/package_name"
            android:id="@+id/txt"
            android:layout_
            android:layout_
            android:layout_centerVertical="true"
            android:layout_marginLeft="41dp"
            android:gravity="center_vertical"
            android:text="text"
            android:textColor="#000"
            android:textSize="23sp"
            custom:typeFace="metanormal"/>

您可以使用 setTypeFace 方法以编程方式更改字体 如果您想从此视图中使用多个命名空间,也可以将自定义命名空间移动到父布局中

快乐编码:)

【讨论】:

简单直接的答案。【参考方案5】:

下面的方法,在 onCreate() 中调用并传递您最外层的 ViewGroup,将适用于除动态创建的文本(即动态列表、警报等)之外的所有内容。获取最外层 ViewGroup 的一种简单方法是在您的任何一个视图上使用 getRootView。

public void onCreate(Bundle savedInstanceState)
    //onCreate code...
    EditText text = (EditText) findViewById(R.id.editText1);
    setTypeFaceForViewGroup((ViewGroup) text.getRootView());


private void setTypeFaceForViewGroup(ViewGroup vg)

    for (int i = 0; i < vg.getChildCount(); i++) 

            if (vg.getChildAt(i) instanceof ViewGroup)
                setTypeFaceForViewGroup((ViewGroup) vg.getChildAt(i));

            else if (vg.getChildAt(i) instanceof TextView)
                ((TextView) vg.getChildAt(i)).setTypeface(Typeface.createFromAsset(getAssets(), "fonts/Your_Font.ttf"));

    


这也应该适用于动态内容,你只需要调用它,传入你创建的任何东西,就在你创建它之后(虽然我还没有测试过)。

为了节省内存,您可能希望将字体设为静态变量,而不是像我在这里那样每次循环运行时都创建一个新变量。

【讨论】:

我不推荐此解决方案,因为您正在为要应用它的每个元素创建相同字体的新实例。这可能会导致内存问题。 这在我最后的笔记中有所提及。【参考方案6】:

如果您正在寻找更通用的编程解决方案,我创建了一个静态类,可用于设置整个视图(活动 UI)的字体。请注意,我正在使用 Mono (C#),但您可以使用 Java 轻松实现它。

您可以将要自定义的布局或特定视图传递给此类。如果你想变得超级高效,你可以使用单例模式来实现它。

public static class AndroidTypefaceUtility 

    static AndroidTypefaceUtility()
    
    
    //Refer to the code block beneath this one, to see how to create a typeface.
    public static void SetTypefaceOfView(View view, Typeface customTypeface)
    
    if (customTypeface != null && view != null)
    
            try
            
                if (view is TextView)
                    (view as TextView).Typeface = customTypeface;
                else if (view is Button)
                    (view as Button).Typeface = customTypeface;
                else if (view is EditText)
                    (view as EditText).Typeface = customTypeface;
                else if (view is ViewGroup)
                    SetTypefaceOfViewGroup((view as ViewGroup), customTypeface);
                else
                    Console.Error.WriteLine("AndroidTypefaceUtility: 0 is type of 1 and does not have a typeface property", view.Id, typeof(View));
                
                catch (Exception ex)
                
                    Console.Error.WriteLine("AndroidTypefaceUtility threw:\n0\n1", ex.GetType(), ex.StackTrace);
                    throw ex;
                
            
            else
            
                Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / view parameter should not be null");
            
        

        public static void SetTypefaceOfViewGroup(ViewGroup layout, Typeface customTypeface)
        
            if (customTypeface != null && layout != null)
            
                for (int i = 0; i < layout.ChildCount; i++)
                
                    SetTypefaceOfView(layout.GetChildAt(i), customTypeface);
                
            
            else
            
                Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / layout parameter should not be null");
            
        

    

在您的活动中,您需要创建一个字体对象。我使用放置在我的 Resources/Assets/ 目录中的 .ttf 文件在 OnCreate() 中创建我的。确保该文件在其属性中标记为 Android 资产。

protected override void OnCreate(Bundle bundle)
               
    ...
    LinearLayout rootLayout = (LinearLayout)FindViewById<LinearLayout>(Resource.Id.signInView_LinearLayout);
    Typeface allerTypeface = Typeface.CreateFromAsset(base.Assets,"Aller_Rg.ttf");
    AndroidTypefaceUtility.SetTypefaceOfViewGroup(rootLayout, allerTypeface);

【讨论】:

【参考方案7】:

很遗憾,Android 没有提供您想要的快速、简单和干净的方式来更改整个应用的字体。但最近我研究了这个问题,并创建了一些工具,让您无需任何编码即可更改字体(您可以通过 xml、样式甚至文本外观来完成这一切)。它们基于您在此处其他答案中看到的类似解决方案,但具有更大的灵活性。您可以在 this blog 上阅读所有相关信息,并查看 github 项目 here。

以下是如何应用这些工具的示例。把你所有的字体文件放在assets/fonts/。然后,在 xml 文件中声明这些字体(例如 res/xml/fonts.xml)并在您的应用程序中尽早使用 TypefaceManager.initialize(this, R.xml.fonts); 加载此文件(例如,在您的 Application 类的 onCreate 中)。 xml 文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<familyset>

    <!-- Some Font. Can be referenced with 'someFont' or 'aspergit' -->
    <family>
        <nameset>
            <name>aspergit</name>
            <name>someFont</name>
        </nameset>
        <fileset>
            <file>Aspergit.ttf</file>
            <file>Aspergit Bold.ttf</file>
            <file>Aspergit Italic.ttf</file>
            <file>Aspergit Bold Italic.ttf</file>
        </fileset>
    </family>

    <!-- Another Font. Can be referenced with 'anotherFont' or 'bodoni' -->
    <family>
        <nameset>
            <name>bodoni</name>
            <name>anotherFont</name>
        </nameset>
        <fileset>
            <file>BodoniFLF-Roman.ttf</file>
            <file>BodoniFLF-Bold.ttf</file>
        </fileset>
    </family>

</familyset>

现在您可以在您的样式或 xml 中使用这些字体(前提是您使用我上面提到的工具),方法是在您的 xml 布局中使用自定义 UI 元素 com.innovattic.font.FontTextView。您可以在下面看到如何将字体应用于整个应用程序中的所有文本,只需编辑res/values/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">

    <!-- Application theme -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <item name="android:textViewStyle">@style/MyTextViewStyle</item>
    </style>

    <!-- Style to use for ALL text views (including FontTextView) -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="MyTextViewStyle" parent="@android:style/Widget.Holo.Light.TextView">
        <item name="android:textAppearance">@style/MyTextAppearance</item>
    </style>

    <!-- Text appearance to use for ALL text views (including FontTextView) -->
    <!-- Use a different parent if you don't want Holo Light -->
    <style name="MyTextAppearance" parent="@android:style/TextAppearance.Holo">
        <!-- Alternatively, reference this font with the name "aspergit" -->
        <!-- Note that only our own TextView's will use the font attribute -->
        <item name="flFont">someFont</item>
        <item name="android:textStyle">bold|italic</item>
    </style>

    <!-- Alternative style, maybe for some other widget -->
    <style name="StylishFont">
        <item name="flFont">anotherFont</item>
        <item name="android:textStyle">normal</item>
    </style>

</resources>

附随res/layout/layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_
    android:layout_
    tools:context=".MainActivity" >

    <!-- This text view is styled with the app theme -->
    <com.innovattic.font.FontTextView
        android:layout_
        android:layout_
        android:text="This uses my font in bold italic style" />

    <!-- This text view is styled here and overrides the app theme -->
    <com.innovattic.font.FontTextView
        android:layout_
        android:layout_
        app:flFont="anotherFont"
        android:textStyle="normal"
        android:text="This uses another font in normal style" />

    <!-- This text view is styled with a style and overrides the app theme -->
    <com.innovattic.font.FontTextView
        style="@style/StylishFont"
        android:layout_
        android:layout_
        android:text="This also uses another font in normal style" />

</LinearLayout>

不要忘记在您的 Android 清单中应用主题。

【讨论】:

【参考方案8】:

我想为leocadiotine 的出色解决方案添加注释。这是完美的,但是当多次使用这个自定义 TextView 时会减慢应用程序的速度,因为它必须在每次创建 textview 时访问资产。我建议在Adapters中使用View Holder pattern之类的东西,我写了一个例子:

public class Fonts 

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

    public static Typeface getTypeface(Context ctx, String fontName) 
        Typeface typeface = typefaces.get(fontName);
        if (typeface == null) 
            typeface = Typeface.createFromAsset(ctx.getAssets(), fontName);
            typefaces.put(fontName, typeface);
        
        return typeface;
     

通过这种方式,应用程序对每个资产只访问一次资产,并将它们保存在内存中以备不时之需。

【讨论】:

【参考方案9】:

我不知道它是否会改变整个应用程序,但我已经设法改变了一些通过这样做无法改变的组件:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lucida Sans Unicode.ttf");
Typeface.class.getField("DEFAULT").setAccessible(true);
Typeface.class.getField("DEFAULT_BOLD").setAccessible(true);
Typeface.class.getField("DEFAULT").set(null, tf);
Typeface.class.getField("DEFAULT_BOLD").set(null, tf);

【讨论】:

@richard,我想根据语言环境设置自定义字体,例如,我想在我们使用英语语言环境时设置 Arial TTF,当我使用韩语语言环境时设置哥特体 TTF 【参考方案10】:

我在这个链接找到了一步一步的信息,链接:https://github.com/jaydipumaretiya/CustomTypeface/

在android中有很多正确使用字体的方法,你必须把你的字体文件放在 直接在 main 下的 assets 文件夹,并且可以在运行时使用它。

其他最简单的方法是使用默认库在您的 xml 文件中设置字体。 我更喜欢这个自定义字体库来将字体设置为 TextView、EditText、Button、CheckBox、 android中的RadioButton和AutoCompleteTextView等wedget。

【讨论】:

【参考方案11】:

Android 8.0(API 级别 26)引入了一项新功能,Fonts in XML。您可以创建一个 fontfamily 文件并将其设置在 styles.xml 中。

要将字体添加为资源,请在 Android 中执行以下步骤 工作室:

1.右键res文件夹,进入New > Android资源目录。将出现“新建资源目录”窗口。

2.在资源类型列表中,选择字体,然后单击确定。注意:资源目录的名称必须是字体。

3.在字体文件夹中添加您的字体文件。

要创建字体系列,请执行以下步骤:

1.右键单击字体文件夹并转到新建>字体资源文件。将出现“新建资源文件”窗口。

2.输入文件名,然后单击“确定”。新的字体资源 XML 在编辑器中打开。

3. 将每个字体文件、样式和粗细属性包含在元素中。以下 XML 说明了添加与字体相关的属性 在字体资源 XML 中:

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

为样式添加字体

打开styles.xml,给字体文件设置fontFamily属性 你想访问。

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

来源:Fonts in XML

【讨论】:

【参考方案12】:

要使用外部字体,请先下载 .tff 格式的字体 Google font- Roboto

如下图所示添加字体资源文件夹

创建字体资源文件夹后,将下载的 .tff 字体复制并粘贴到“字体”文件夹中。 (确保名称格式正确。)

在您的 theme.xml 或任何使用 android:fontFamily="@font/splashfont" 属性的布局中引用字体。

如果您希望字体应用于整个应用程序,请在您的 theme.xml 中设置 fontfamily。这就是你在 theme.xml 文件中的做法

<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.FishPott" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <!-- Primary brand color. -->
    <item name="colorPrimary">@color/color_black_level_1</item>
    <item name="colorPrimaryVariant">@color/color_black_level_2</item>
    <item name="colorOnPrimary">@color/white</item>
    <!-- Secondary brand color. -->
    <item name="colorSecondary">@color/color_black_level_1</item>
    <item name="colorSecondaryVariant">@color/color_black_level_2</item>
    <item name="colorOnSecondary">@color/color_white_level_1</item>
    <!-- Status bar color. -->
    <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
    <!-- Customize your theme here. -->
    <item name="android:fontFamily">@font/robotoregular</item>
</style>

【讨论】:

以上是关于Android:想要为整个应用程序而不是运行时设置自定义字体的主要内容,如果未能解决你的问题,请参考以下文章

如何使用CSS为文本的宽度而不是整个元素的宽度设置背景色?

如何在GoLand中运行整个项目?

如何仅将整个应用程序设置为纵向模式?

Android - 如何在代码中设置首选项

Android 谷歌地图使用 GPS 定位而不是网络

为整个 appdomain 定义文化