寫在開始
對比ios系統(tǒng),Android中默認(rèn)的字體在中文顯示上是十分難看的,尤其是字號比較大的時候,默認(rèn)字體樣式都會感覺比較粗,所以一般對于產(chǎn)品有追求的設(shè)計,都會考慮換一套字體樣式,那么過程中就需要知道一些自定義字體的知識。這里的自定義系列翻譯于一個看過比較好的系列,因?yàn)樵拿科钠悬c(diǎn)少,所以將幾篇文章合在一起翻譯。
原文地址
- Custom Fonts on Android — Quick & Dirty
- Custom Fonts on Android — Extending TextView
- Custom Fonts on Android — Using Font Styles
為什么自定義字體
Android系統(tǒng)默認(rèn)使用的是一款叫Roboto的字體。如果你想要突出一個元素,那么會有很多的選擇:顏色,大小,樣式(粗體,斜體,普通),另一種方式就是使用不同于系統(tǒng)的字體來裝飾你的view。
單個用法的最快實(shí)現(xiàn)
首先你需要去找一些想使用的 ttf
文件,比較好的地方有1001 Free Fonts或者是Google Fonts。
然后,將這個文件放在Android項目的 assets
文件夾下面。
然后就是將這個字體運(yùn)用到你想要改變的 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
然后就結(jié)束了,如果想要改變一個Textview的字體就是這么簡單,最好的情況就是上面的代碼在 onCreate()
方法中進(jìn)行調(diào)用。
如果你只想用在單個實(shí)例上那么這種方法是足夠的,但是如果你想要給app中成千上萬的view都使用自定義字體的話,這可能就不是一個好方法了,畢竟我們不可能在每個初始化的地方都去加上上面那一段。
提供字體內(nèi)存緩存
雖然Android現(xiàn)在已經(jīng)很流暢,但是我們依然應(yīng)該考慮優(yōu)化性能。所以,我們應(yīng)該把自定義的字體緩存起來,這樣就不用每次去初始化,在 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
文件夾,接下來就能實(shí)現(xiàn)一個繼承自 TextView
的類。
繼承TextView
首先來創(chuàng)建一個類繼承自 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);
}
}
開始的三個都是構(gòu)造函數(shù),里面都調(diào)用了 applyCustomFont()
方法,然后從上面的 FontCache
類中拿到緩存的字體文件,這樣就不用每個view都去重復(fù)的從 Assets中取字體,節(jié)約了資源,最后將取到的字體設(shè)置到 setTypeface()
中。
使用自定義類
現(xiàn)在我們只需要在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/>
,這個前面的是全部的包名,然后就會自己應(yīng)用字體。
但是使用中會發(fā)現(xiàn),雖然一些TextView的屬性比如 textSize
能正常的顯示,但是 textStyle
這個屬性并不能正常的生效。
添加每個ttf文件
首先將同一個系列的三種樣式的 ttf
文件都加到 assets
中
在XML中使用textStyle屬性
在前面已經(jīng)講解了自定義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"/>
一般情況下,我們更希望使用的是標(biāo)準(zhǔn)的 android:textStyle
而不是用一個自定義的屬性 customfont:textStyle
。但是像上面這樣的屬性直接放上去肯定是不能生效的,還需要再加一些代碼才行。
提示:如果你對使用 customfont:textStyle
的方式比較感興趣,那么下一篇文章中會介紹如何使用。
實(shí)現(xiàn)CustomFontTextView
為了能繼續(xù)的使用系統(tǒng)的 android:textStyle
屬性,需要一些步驟。
首先需要在代碼拿到這個屬性的信息,這只需要一行代碼:
int textStyle = attrs.getAttributeIntValue(ANDROID_SCHEMA, "textStyle", Typeface.NORMAL);
attr
這個值是來自 TextView
的第二個構(gòu)造函數(shù)中的參數(shù),我們可以使用這個對象的 getAttributeIntValue()
方法獲取XML的屬性。
先看一下上面代碼中的 ANDROID_SCHEMA
這個參數(shù),這個是一個常量,定義在XML的最頂部中(xmlns:android="http://schemas.android.com/apk/res/android" ),第二個參數(shù)就是定義的屬性名,最后一個參數(shù)是默認(rèn)值,如果這個屬性沒有設(shè)置,那么就會選擇 Typeface.NORMAL
。
當(dāng)我們考慮了樣式之后,完善一下代碼,全部的代碼看起來就像下面這樣。
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);
}
}
這樣我們的自定義字體就能使用標(biāo)準(zhǔn)的應(yīng)用字體樣式 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>
這個文件在模擬器上顯示的效果就像下面這樣。