Android自定义字体实践

作者: sheepm | 来源:发表于2016-09-26 13:39 被阅读3153次

写在开始

对比ios系统,Android中默认的字体在中文显示上是十分难看的,尤其是字号比较大的时候,默认字体样式都会感觉比较粗,所以一般对于产品有追求的设计,都会考虑换一套字体样式,那么过程中就需要知道一些自定义字体的知识。这里的自定义系列翻译于一个看过比较好的系列,因为原文每篇的篇幅有点少,所以将几篇文章合在一起翻译。

原文地址

为什么自定义字体

Android系统默认使用的是一款叫Roboto的字体。如果你想要突出一个元素,那么会有很多的选择:颜色,大小,样式(粗体,斜体,普通),另一种方式就是使用不同于系统的字体来装饰你的view。

单个用法的最快实现

首先你需要去找一些想使用的 ttf 文件,比较好的地方有1001 Free Fonts或者是Google Fonts
然后,将这个文件放在Android项目的 assets 文件夹下面。

font files in our eat foody project
然后就是将这个字体运用到你想要改变的 TextView 上面。
TextView textview = (TextView) findViewById(R.id.your_referenced_textview);
 // adjust this line to get the TextView you want to change

Typeface typeface = Typeface.createFromAsset(getAssets(),"SourceSansPro-Regular.ttf"); // create a typeface from the raw ttf  
textview.setTypeface(typeface); // apply the typeface to the textview 

然后就结束了,如果想要改变一个Textview的字体就是这么简单,最好的情况就是上面的代码在 onCreate() 方法中进行调用。
如果你只想用在单个实例上那么这种方法是足够的,但是如果你想要给app中成千上万的view都使用自定义字体的话,这可能就不是一个好方法了,毕竟我们不可能在每个初始化的地方都去加上上面那一段。

提供字体内存缓存

虽然Android现在已经很流畅,但是我们依然应该考虑优化性能。所以,我们应该把自定义的字体缓存起来,这样就不用每次去初始化,在 britzl on stackoverflow上有一个比较好的答案。

public class FontCache {

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

    public static Typeface getTypeface(String fontname, Context context) {
        Typeface typeface = fontCache.get(fontname);

        if (typeface == null) {
            try {
                typeface = Typeface.createFromAsset(context.getAssets(), fontname);
            } catch (Exception e) {
                return null;
            }

            fontCache.put(fontname, typeface);
        }

        return typeface;
    }
}

缓存下字体就能让我们不用一直去操作 Assets 文件夹,接下来就能实现一个继承自 TextView 的类。

继承TextView

首先来创建一个类继承自 TextView,这样就能在 XML 中来使用,它继承了 TextView所有的属性和功能,然后再加上自定义的字体。

public class EatFoodyTextView extends TextView {

    public EatFoodyTextView(Context context) {
        super(context);

        applyCustomFont(context);
    }

    public EatFoodyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);

        applyCustomFont(context);
    }

    public EatFoodyTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        applyCustomFont(context);
    }

    private void applyCustomFont(Context context) {
        Typeface customFont = FontCache.getTypeface("SourceSansPro-Regular.ttf", context);
        setTypeface(customFont);
    }
}

开始的三个都是构造函数,里面都调用了 applyCustomFont() 方法,然后从上面的 FontCache 类中拿到缓存的字体文件,这样就不用每个view都去重复的从 Assets中取字体,节约了资源,最后将取到的字体设置到 setTypeface() 中。

使用自定义类

现在我们只需要在XML中直接使用,不需要再写其他的java代码,

<RelativeLayout  
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.futurestudio.foody.views.EatFoodyTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/eat_foody_green_dark"
        android:textSize="20sp"
        android:text="Future Studio Blog"
        android:layout_marginBottom="24dp"/>

</RelativeLayout> 

我们可以依然使用TextView的其他属性,(textSize,textColor之类的),只需要把 <TextView/> 替换成 <com.futurestudio.foody.views.EatFoodyTextView/> ,这个前面的是全部的包名,然后就会自己应用字体。
但是使用中会发现,虽然一些TextView的属性比如 textSize 能正常的显示,但是 textStyle 这个属性并不能正常的生效。

添加每个ttf文件

首先将同一个系列的三种样式的 ttf 文件都加到 assets

Assets Folder with Font Files for Each Style

在XML中使用textStyle属性

在前面已经讲解了自定义view的使用

<io.futurestud.tutorials.customfont.CustomFontTextView  
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="12dp"
    android:text="http://futurestud.io/blog/"
    android:textSize="18sp"
    android:textStyle="bold"/>

一般情况下,我们更希望使用的是标准的 android:textStyle 而不是用一个自定义的属性 customfont:textStyle 。但是像上面这样的属性直接放上去肯定是不能生效的,还需要再加一些代码才行。
提示:如果你对使用 customfont:textStyle 的方式比较感兴趣,那么下一篇文章中会介绍如何使用。

实现CustomFontTextView

为了能继续的使用系统的 android:textStyle 属性,需要一些步骤。
首先需要在代码拿到这个属性的信息,这只需要一行代码:

int textStyle = attrs.getAttributeIntValue(ANDROID_SCHEMA, "textStyle", Typeface.NORMAL); 

attr 这个值是来自 TextView 的第二个构造函数中的参数,我们可以使用这个对象的 getAttributeIntValue() 方法获取XML的属性。
先看一下上面代码中的 ANDROID_SCHEMA 这个参数,这个是一个常量,定义在XML的最顶部中(xmlns:android="http://schemas.android.com/apk/res/android" ),第二个参数就是定义的属性名,最后一个参数是默认值,如果这个属性没有设置,那么就会选择 Typeface.NORMAL
当我们考虑了样式之后,完善一下代码,全部的代码看起来就像下面这样。

public class CustomFontTextView extends TextView {

    public static final String ANDROID_SCHEMA = "http://schemas.android.com/apk/res/android";

    public CustomFontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);

        applyCustomFont(context, attrs);
    }

    public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        applyCustomFont(context, attrs);
    }

    private void applyCustomFont(Context context, AttributeSet attrs) {
        int textStyle = attrs.getAttributeIntValue(ANDROID_SCHEMA, "textStyle", Typeface.NORMAL);

        Typeface customFont = selectTypeface(context, textStyle);
        setTypeface(customFont);
    }

    private Typeface selectTypeface(Context context, int textStyle) {
        /*
        * information about the TextView textStyle:
        * http://developer.android.com/reference/android/R.styleable.html#TextView_textStyle
        */
        switch (textStyle) {
            case Typeface.BOLD: // bold
                return FontCache.getTypeface("SourceSansPro-Bold.ttf", context);

            case Typeface.ITALIC: // italic
                return FontCache.getTypeface("SourceSansPro-Italic.ttf", context);

            case Typeface.BOLD_ITALIC: // bold italic
                return FontCache.getTypeface("SourceSansPro-BoldItalic.ttf", context);

            case Typeface.NORMAL: // regular
            default:
                return FontCache.getTypeface("SourceSansPro-Regular.ttf", context);
        }
}

这样我们的自定义字体就能使用标准的应用字体样式 textStyle

看看成果

首先我们在XML中写一些布局,包括原生的 Roboto 字体以及不同形式的自定义字体。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:text="http://futurestud.io/blog/"
        android:textSize="18sp"/>

    <io.futurestud.tutorials.customfont.CustomFontTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:text="http://futurestud.io/blog/"
        android:textSize="18sp"/>

    <io.futurestud.tutorials.customfont.CustomFontTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:text="http://futurestud.io/blog/"
        android:textSize="18sp"
        android:textStyle="bold"/>

    <io.futurestud.tutorials.customfont.CustomFontTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:text="http://futurestud.io/blog/"
        android:textSize="18sp"
        android:textStyle="italic"/>

</LinearLayout> 

这个文件在模拟器上显示的效果就像下面这样。

Fonts from top to bottom: Roboto, Source Sans Pro, Source Sans Pro Bold, Source Sans Pro Italic

相关文章

  • android自定义字体

    Android O通过字体资源支持自定义字体,支持.otf(OpenType)和.ttf(TrueType)字体格...

  • Android自定义字体实践

    写在开始 对比ios系统,Android中默认的字体在中文显示上是十分难看的,尤其是字号比较大的时候,默认字体样式...

  • Android字体库Calligraphy源码解析

    什么是Calligraphy 如果你没有看过上一篇文章 Android自定义字体实践 ,那么可以先点一下前置技能,...

  • Android自定义字体

    文章目的:快速入门Android中自定义各种字体! 前言:我们都知道,Android中默认的字体是黑体,而大多数a...

  • Android自定义字体设置

    Android自定义字体设置 1.typeface、fontFamily、textStyle介绍 1.typefa...

  • Android高级

    Android自定义Lint实践 Android动态加载黑科技 动态创建Activity模式 Android系统预...

  • Android 自定义字体

    说明 在一些应用中,有改变字体,或者某些页面有特殊字体要求时,Android自身的字体满足不了时,需要自定义字体,...

  • Android自定义字体

    Android 自定义字体 1. Android默认方法 为每个view单独设置Typeface. 这种方法可以扩...

  • Android上的自定义字体 - 通过XML进行动态字体选择

    前言 这是我们系列自定义字体在Android上的第2篇文章。在之前,我们已经看到如何使用自定义字体并将不同的样式应...

  • Android 自定义字体方案

    在应用中需要配置不同的字体,而 Android 只能在 xml 中配置系统默认提供的四种字体,需要自定义的字体都需...

网友评论

  • 酷酷阿梦:请问在xml中
    com.futurestudio.foody.views.EatFoodyTextView
    前面的com.futurestudio.foody.views.这段是什么意思?包名吗
  • Jooyer:非常喜欢

本文标题:Android自定义字体实践

本文链接:https://www.haomeiwen.com/subject/hmjfyttx.html