自定义字体和XML布局(Android)

174

我正在尝试在Android中使用XML文件定义GUI布局。据我所知,无法在XML文件中指定小部件应使用自定义字体(例如放置在assets / font /中的字体),您只能使用系统安装的字体。

我知道,在Java代码中,我可以使用唯一ID手动更改每个小部件的字体。或者,我可以在Java中迭代所有小部件以进行此更改,但这可能会非常慢。

我还有哪些选项?是否有更好的方法来制作具有自定义外观的小部件? 我不想为每个新添加的小部件手动更改字体。


69
DrDefrost,请接受一些答案,这样你就会在这个网站上获得更多的回复。 - Ken
1
这里还有一个类似的问题:https://dev59.com/6Wox5IYBdhLWcg3wsGWC - Vins
更新于05/2017:“支持库26.0 Beta为在运行Android API 14及更高版本的设备上使用XML字体功能提供支持。”参见:https://developer.android.com/preview/features/fonts-in-xml.html#using-support-lib - albert c braun
18个回答

2
我可以为这个问题提供一个简单的答案,而不需要扩展TextView并实现冗长的代码。
代码:
 TextView tv = (TextView) findViewById(R.id.textview1);
    tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));

将自定义字体文件像往常一样放在资产文件夹中,然后尝试此方法。这对我有效。 我只是不明白为什么Peter为这个简单的事情提供了如此庞大的代码,或者他的答案是在旧版本中给出的。

1
有两种自定义字体的方式:
!!! 我在assets/fonts/iran_sans.ttf中自定义了字体
方式1: 使用Refrection Typeface.class ||| 最佳方式来自定义字体。
在继承Application的类中调用FontsOverride.setDefaultFont(),这段代码会导致所有软件字体被更改,甚至是Toast的字体。

AppController.java

public class AppController extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        //Initial Font
        FontsOverride.setDefaultFont(getApplicationContext(), "MONOSPACE", "fonts/iran_sans.ttf");

    }
}

FontsOverride.java

public class FontsOverride {

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

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

方法2:使用setTypeface

对于特殊视图,只需调用setTypeface()更改字体。

CTextView.java

public class CTextView extends TextView {

    public CTextView(Context context) {
        super(context);
        init(context,null);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context,attrs);
    }

    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs);
    }

    public void init(Context context, @Nullable AttributeSet attrs) {

        if (isInEditMode())
            return;

        // use setTypeface for change font this view
        setTypeface(FontUtils.getTypeface("fonts/iran_sans.ttf"));

    }
}

FontUtils.java

public class FontUtils {

    private static Hashtable<String, Typeface> fontCache = new Hashtable<>();

    public static Typeface getTypeface(String fontName) {
        Typeface tf = fontCache.get(fontName);
        if (tf == null) {
            try {
                tf = Typeface.createFromAsset(AppController.getInstance().getApplicationContext().getAssets(), fontName);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            fontCache.put(fontName, tf);
        }
        return tf;
    }

}

1
Peter的回答是最好的,但是你可以使用Android中的styles.xml来自定义应用程序中所有textview的字体,从而进一步改进它。
我的代码在这里

0
你可以轻松地创建自定义的TextView类:-
所以,首先需要做的是创建一个继承自AppCompatTextView的Custom TextView类。
public class CustomTextView extends AppCompatTextView {
    private int mFont = FontUtils.FONTS_NORMAL;
    boolean fontApplied;

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

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

    public CustomTextView(Context context) {
        super(context);
        init(null, context);
    }

    protected void init(AttributeSet attrs, Context cxt) {
        if (!fontApplied) {
            if (attrs != null) {
                mFont = attrs.getAttributeIntValue(
                        "http://schemas.android.com/apk/res-auto", "Lato-Regular.ttf",
                        -1);
            }
            Typeface typeface = getTypeface();
            int typefaceStyle = Typeface.NORMAL;
            if (typeface != null) {
                typefaceStyle = typeface.getStyle();
            }
            if (mFont > FontUtils.FONTS) {
                typefaceStyle = mFont;
            }
            FontUtils.applyFont(this, typefaceStyle);
            fontApplied = true;
        }
    }
}

现在,每次自定义文本视图调用时,我们将从属性中获取int值:int fontValue = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto","Lato-Regular.ttf",-1)

或者

我们还可以从我们在xml中设置的视图中获取getTypeface()(android:textStyle="bold|normal|italic")。所以你想做什么就做什么。

现在,我们制作了FontUtils,以便将任何.ttf字体设置到我们的视图中。

public class FontUtils {

    public static final int FONTS = 1;
    public static final int FONTS_NORMAL = 2;
    public static final int FONTS_BOLD = 3;
    public static final int FONTS_BOLD1 = 4;

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

    static Typeface getFonts(Context context, String name) {
        Typeface typeface = TYPEFACE.get(name);
        if (typeface == null) {
            typeface = Typeface.createFromAsset(context.getAssets(), name);
            TYPEFACE.put(name, typeface);
        }
        return typeface;
    }

    public static void applyFont(TextView tv, int typefaceStyle) {

        Context cxt = tv.getContext();
        Typeface typeface;

        if(typefaceStyle == Typeface.BOLD_ITALIC) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
        }else if (typefaceStyle == Typeface.BOLD || typefaceStyle == SD_FONTS_BOLD|| typefaceStyle == FONTS_BOLD1) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-SemiBold.ttf");
        } else if (typefaceStyle == Typeface.ITALIC) {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Thin.ttf");
        } else {
            typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
        }
        if (typeface != null) {
            tv.setTypeface(typeface);
        }
    }
}

0

有一点需要注意,从Android 8.0(API级别26)开始,您可以在XML中使用自定义字体

您可以按照以下方式将自定义字体应用于整个应用程序。

  1. 将字体放入文件夹res/font中。

  2. res/values/styles.xml中,在应用程序主题中使用它。 <style name="AppTheme" parent="{任何你喜欢的}"> <item name="android:fontFamily">@font/myfont</item> </style>


0

-1

-5

1
啊哈 - “widget” 这个词的著名双重用途再次出现了! - Carl Whalley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接