螢幕適配的頂級淫技:使用 TextView 來顯示圖片

OCN_Yang發表於2017-11-09

今天我們來介紹一種用 TextView 代替並顯示圖片,以達到App優化及圖示自適應的效果。而圖片大小等的設定依舊使用 TextView 的各原生方法。

這裡先放上本文的GitHub 連結:github.com/OCNYang/Fon…

首先,我們先來看一下效果:

這些真的只是TextView文字
這些真的只是TextView文字

如果你看到上面這張圖片,第一反映你可能認為都是用ImageView去顯示的,那你就錯了,這些全都是用TextView實現的(當然更不可能是給 TextView 設定了背景圖)。

平時我們在開發中,圖片可謂是處處可見且必不可少的一部分,為了想盡辦法讓圖片達到適配的效果我們可能需要:
根據不同解析度來提供多套圖,暫且不說這種方式是否麻煩,正常情況下我們切的三套或更多套圖有時候總在有些機型上的效果不盡人意。
可能這時候你想到了用 .9圖片,這時候且不說你們家 UI 妹子會不會單獨的為我們 Android 端提供 .9圖片 (姑且相信你們家UI會製作.9),但是 .9圖片 是有一定的侷限性的,它只能是圖片部分割槽域拉伸。

這篇文章也並不是去介紹如何去做圖片的適配,而是介紹一種利用字型庫的方式,我們用 TextView 的形式去顯示圖片,而且我們還可以正常的使用 android:textSize 屬性來隨意設定圖片的大小!

其實這裡通過 TextView 來顯示圖片的方式,我更願意更準確的說成是通過 TextView 來顯示圖示,因為這裡的圖片不是真正意義上的大圖而是相當於可以隨意拉伸的向量圖。當然,如果你願意你也可以用這種方式來顯示圖片。

囉嗦這麼多,你的大刀是不是早就飢渴難耐了?其實這種方式很容易就能實現,只是通過給 TextView 設定一種字型,不要著急,馬上開始。

為TextView設定字型

大家都知道,在 android 中,我們如果要更換字型,除了要引入我們需要的字型庫外,還需要給我們的 TextView 去手動設定使用的字型,如何去設定呢?其實很簡單。

textView.setTypeface(Typeface tf);  複製程式碼

儘管就這麼一行程式碼,但是,在我們專案中肯定會存在大量的TextView,難道我們要一個個的去動手設定嗎?想想這也是一件很頭疼的事,下面就介紹一種方便的方法,一行程式碼解決字型設定的問題。

方法一:工具類 & 遞迴遍歷

在看程式碼之前,先來看看思路,其實思路很簡單,我們提供一個根佈局,寫一個方法去遞迴遍歷整個根佈局,如果發現是textView,則設定字型。思路很簡單,相信程式碼也很簡單,就是一個遞迴方法。

public class FontHelper {
    public static final String DEF_FONT = "fonts/ocnyangfont.ttf";

    public static final void injectFont(View rootView) {
        injectFont(rootView, Typeface.createFromAsset(rootView.getContext().getAssets(),
                DEF_FONT));
    }

    private static void injectFont(View rootView, Typeface typeface) {
        if (rootView instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) rootView;
            int childViewCount = viewGroup.getChildCount();
            for (int i = 0; i < childViewCount; i++) {
                injectFont(viewGroup.getChildAt(i), typeface);
            }
        } else if (rootView instanceof TextView) {
            ((TextView) rootView).setTypeface(typeface);
        }
    }
} 複製程式碼

定義了一個工具類,這個類提供兩個靜態方法,但是核心都是

public static final void injectFont(View rootView, Typeface tf)複製程式碼

這個方法中,首先我們去判斷我們給的rootView是不是ViewGroup,如果是ViewGroup,則遍歷他的所有子view,然後遞迴去呼叫這個方法,直到全部完成,如果發現某個view是TextView,則我們呼叫setTypeface方法來設定字型。
ok,從這個工具類中我們還可以看到,我們的字型是放在assets/fonts目錄下的。

最後是在activity中使用字型庫,正式利用了上面的工具類,所以我們的程式碼將會很簡單。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    FontHelper.injectFont(findViewById(android.R.id.content));
}複製程式碼

僅僅一行程式碼,FontHelper.injectFont(findViewById(android.R.id.content));
我們就完成了給所有TextView設定字型的工作。

方法二:LayoutInflate

現在對 LayoutInflateFactory 的用法還不太熟悉的,可以先去看一下鴻洋的這篇博文:探究 LayoutInflate setFactory

我們編寫一個自定義的LayoutInflaterFactory:

public class IconFontLayoutFactory implements LayoutInflaterFactory {

    private static Typeface sTypeface;
    private AppCompatDelegate mAppCompatDelegate;

    public IconFontLayoutFactory(Context context,
                                 AppCompatDelegate appCompatDelegate) {
        if (sTypeface == null) {
            sTypeface = Typeface.createFromAsset(context.getAssets(),
                    "fonts/ocnyangfont.ttf");
        }
        mAppCompatDelegate = appCompatDelegate;
    }

    @Override
    public View onCreateView(View parent, String name, Context context,
                             AttributeSet attrs) {
        View view = mAppCompatDelegate.createView(parent, name, context, attrs);
        if (view instanceof TextView) {
            ((TextView) view).setTypeface(sTypeface);
        }
        return view;
    }
}複製程式碼

字型檔案我們還是放在 assets/fonts 目錄下。

然後你可以在你的BaseActivity的onCreate中,呼叫如下程式碼:

@Override
protected void onCreate(Bundle savedInstanceState) {

        LayoutInflaterCompat.setFactory(getLayoutInflater(),
                new IconFontLayoutFactory(this,getDelegate()));

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
}複製程式碼

注意一定要在super.onCreate前呼叫即可。

該方式可以在TextView及其子類物件建立完成時,就可以為其呼叫setTypeFace,非常的高效。
而對於字型庫的載入,如果有需要,你甚至可以採用懶載入的方式,在SplashActivity中對其初始化。

這裡提供是兩種全域性設定的方式。
有時候我們只是需要給部分 TextView 設定,這時候大家可以選擇手動單獨給特定的 TextView 設定,也可以通過自定義 View 的方案來實現(在構造方法中去設定 TypeFace,我個人也比較提倡這種方式,使用上相對靈活,也很簡單這裡就不囉嗦了,詳細程式碼可以到這裡下載 本文原始碼 內檢視)。

那上面這些只是如何設定字型的方法,可能你也早就知道了,字型是字型,也不是圖片呀,大兄弟莫慌,下面就給你如何介紹一種酷炫的字型庫和製作自己獨特的圖片字型庫的方法。

fontawesome 字型庫的使用

在開始使用之前,我們我們需要到
github.com/FortAwesome…
下載這個字型庫(不想麻煩,本文 原始碼 也包含有)。下載下來以後,你會看到有很多目錄和檔案,沒關係,我們只需要一個檔案-fontawesome-webfont.ttf,這個檔案位於/fonts/目錄下。將這個ttf檔案copy到你專案的assets目錄下,按照慣例或者說是共識,我們可能是將它放到assets/fonts這個目錄下(注意,沒有這個目錄的話,建立它!)。

ok, 準備工作都做好了,那我們就開始使用它吧,看我的xml佈局檔案:

<LinearLayout
    //...
    >

    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_margin="10dp"
        android:textSize="58sp"
        android:textColor="#ff995533"
        android:layout_height="wrap_content"
        android:text=""/>

    <TextView
        android:id="@+id/text2"
        android:layout_width="match_parent"
        android:layout_margin="10dp"
        android:textSize="118sp"
        android:textColor="#ff9ff533"
        android:layout_height="wrap_content"
        android:text=""/>

    //...

</LinearLayout>複製程式碼

看到這個佈局檔案,我們看到和平時沒什麼區別,給出了textSize或者textColor屬性,不用想這些肯定去控制了我們需要顯示的圖片的大小和顏色!

細心的你會發現這些 TextView 文字好奇怪。其實這些文字對應的就是相對於的圖片。可是,現在我們又遇到了一個問題,我們怎麼知道哪寫文字代表了什麼圖片呢?下面給出一個網址,通過這個網址,大家可以看到實體文字和他對應的圖片的一個對照表。

fortawesome.github.io/Font-Awesom…

本文 原始碼 內我們提供了一個 string.xml 檔案的圖片字元對照表,可以直接在專案中使用。
你也可以在根據自己的需要在上面 string.xml 檔案裡 Ctrl + F 檢索出對應的編碼放到自己的字串檔案裡或直接使用。

哦,對了,不知道大家有沒有發現,這裡我們無意中解決了一個圖片大小的問題,因為我們可以任意改變一個文字的大小,所以,就不需要提供多套圖去適配不同的螢幕了。

這是你可能還是有疑問,Font-Awesome 庫 內提供的圖示雖然很全很美觀,但是不一定能滿足我們所有的需要啊!那現在就教大家如何製作屬於自己的字型庫。

製作屬於自己的圖片字型庫

在自己動手製作圖片字型庫之前,當然要先查詢一些自己喜歡的漂亮的圖示了,下面開啟乾貨福利模式。

圖示乾貨

對於使用,最主要就是找到一些靠譜的素材站點了

www.iconfont.cn/
icomoon.io/app/#/selec…
github.com/mikepenz/An…

第一個站點是阿里提供的圖示庫,基本上可以搜尋到需要的任何圖示,非常方便,也支援顏色和大小的設定,足夠滿足我們的需求:

阿里 iconfont 圖示庫
阿里 iconfont 圖示庫

自定義圖示

無論上面這些網站提供的圖示是多麼的全,可能都無法滿足貪心的你或者你們家追求完美(矯情)到極致的UI,那麼如果App內的圖示部分是自己製作的,再混雜著網路上已有的圖示能打包到一個字型庫麼?
答案當然是肯定的,我們本來就是要製作屬於自己的字型庫嘛!比如你就可以依賴 iconfont.com 這個網站,自行上傳svg圖示,然後就可以自由選擇了。

關於 iconfont 網站的用法可以參考官方手冊(也可以跳過,直接跟著我學習怎麼生成自己的字型庫):
www.iconfont.cn/help/platfo…

按需生成自己的圖示字型庫

我們以 iconfont 庫為例,教大家生成自己圖片字型庫的整個流程(下面所有步驟,大家都無需註冊賬號,就可以直接使用)。

首先在 iconfont 網站上選擇自己要生成到字型庫的圖示,可以選擇網站字型庫中選擇,也可以在我的圖示庫中選擇自己上傳的圖示。把這些圖示新增到庫(即新增到購物車):

選擇喜歡的圖示
選擇喜歡的圖示

新增到購物車
新增到購物車

當你想要生成的字型庫的圖示選擇完成後,在網站右上角點選開啟庫(購物車),在庫裡可以看到自己選擇的所有圖示,確定後點選下載程式碼:

開啟庫,下載程式碼會得到一個壓縮包
開啟庫,下載程式碼會得到一個壓縮包

解壓縮後,可以看到生成的庫
解壓縮後,可以看到生成的庫

在解壓後的資料夾中,我們看到許多檔案。其中以 .ttf 結尾的檔案就是我們生成的自己的字型庫,而 3 個 .html 檔案對應的是不同平臺使用時對應的編碼。而我們在 Android 開發中要使用的編碼是 demo_unicode.html 檔案裡對應的 &#xxxxx; 形式的編碼。

細心的你一定會發現,生成的字型庫裡雖然包含了很多圖示,卻只有小小的幾 KB 的大小,更難能可貴的是無論設定多大的尺寸它依舊能夠儲存一樣的清晰度,當然,你也可以把該方案看成apk瘦身的可選手段之一。

本文Demo原始碼下載地址:github.com/OCNYang/Fon…

參考:
亓斌 - FontAwesome-用TextView顯示圖片
鴻洋 - Android IconFont全攻略
How to Use FontAwesome in an Android App

相關文章