(原創)如何在spannableString中使用自定義字體

最近在作車聯網的產品,主打的是語音交互和導航功能,UI給的導航界面可真是夠酷炫的。但麻煩的事情也來了,裏面的一句話竟然用到了三種字體。界面如圖所示:html

從圖中能夠看出 500m左前方行駛 竟然使用了三種字體,數字一種、英文一種、漢字一種,(這裏不討論拆分三個textview能不能實現的問題,若是能實現也是最無可奈何的辦法,況且你解決了這個,上面那個 -2h30m 你要拆成4個textview嗎?顯然這不合理)咱們知道spannableString是個 很強大的類,能夠經過new typefacespan(family)設置字體,但他們支持的是系統的三種字體,但我還從沒有使用過自定義的字體。爲了解決這個問題我仔細看了關於spannableString的介紹。然而這類文章真的很少,只是從一篇文章中得知能夠經過自定義typefacespan來使用自定義字體。(文章地址:http://www.cnblogs.com/jisheng/archive/2013/01/10/2854088.html)java

如何自定義typefacespan,這東西也沒別人作過先例,無奈只好本身去看源碼:android

 1 /*
 2  * Copyright (C) 2006 The Android Open Source Project
 3  *
 4  * Licensed under the Apache License, Version 2.0 (the "License");
 5  * you may not use this file except in compliance with the License.
 6  * You may obtain a copy of the License at
 7  *
 8  *      http://www.apache.org/licenses/LICENSE-2.0
 9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.text.style;
18 
19 import android.graphics.Paint;
20 import android.graphics.Typeface;
21 import android.os.Parcel;
22 import android.text.ParcelableSpan;
23 import android.text.TextPaint;
24 import android.text.TextUtils;
25 
26 /**
27  * Changes the typeface family of the text to which the span is attached.
28  */
29 public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
30     private final String mFamily;
31 
32     /**
33      * @param family The font family for this typeface.  Examples include
34      * "monospace", "serif", and "sans-serif".
35      */
36     public TypefaceSpan(String family) {
37         mFamily = family;
38     }
39 
40     public TypefaceSpan(Parcel src) {
41         mFamily = src.readString();
42     }
43     
44     public int getSpanTypeId() {
45         return TextUtils.TYPEFACE_SPAN;
46     }
47     
48     public int describeContents() {
49         return 0;
50     }
51 
52     public void writeToParcel(Parcel dest, int flags) {
53         dest.writeString(mFamily);
54     }
55 
56     /**
57      * Returns the font family name.
58      */
59     public String getFamily() {
60         return mFamily;
61     }
62 
63     @Override
64     public void updateDrawState(TextPaint ds) {
65         apply(ds, mFamily);
66     }
67 
68     @Override
69     public void updateMeasureState(TextPaint paint) {
70         apply(paint, mFamily);
71     }
72 
73     private static void apply(Paint paint, String family) {
74         int oldStyle;
75 
76         Typeface old = paint.getTypeface();
77         if (old == null) {
78             oldStyle = 0;
79         } else {
80             oldStyle = old.getStyle();
81         }
82 
83         Typeface tf = Typeface.create(family, oldStyle);
84         int fake = oldStyle & ~tf.getStyle();
85 
86         if ((fake & Typeface.BOLD) != 0) {
87             paint.setFakeBoldText(true);
88         }
89 
90         if ((fake & Typeface.ITALIC) != 0) {
91             paint.setTextSkewX(-0.25f);
92         }
93 
94         paint.setTypeface(tf);
95     }
96 }

從源碼中咱們能夠看到構造函數(36~38行)傳入了一個family的字符串,這個是用來找系統字體的,而後咱們往下看,哪裏用到了這個family(83行):git

咱們經過Typeface.create(family,oldStyle)獲得了一個typeface,而後從86~92行是設置粗體和斜體。也就是說這個地方纔是設置字體的真諦。而咱們知道能夠經過讀取文件的方式獲得自定義的typeface,所以徹底能夠經過掉包的方式實現自定義字體。因而我仿照Typefacespan實現了本身的一個MyTypefaceSpan的類,以下:github

 1 package com.justenjoy.view;
 2 
 3 import android.graphics.Paint;
 4 import android.graphics.Typeface;
 5 import android.text.TextPaint;
 6 import android.text.style.MetricAffectingSpan;
 7 
 8 /**
 9  * 類名:MyTypefaceSpan <br/>
10  * 做者 :王洪賀 <br/>
11  * 描述: <br/>
12  * 2015年7月15日
13  */
14 public class MyTypefaceSpan extends MetricAffectingSpan {
15 
16     private final Typeface typeface;
17 
18     public MyTypefaceSpan(final Typeface typeface) {
19         this.typeface = typeface;
20     }
21 
22     @Override
23     public void updateDrawState(final TextPaint drawState) {
24         apply(drawState);
25     }
26 
27     @Override
28     public void updateMeasureState(final TextPaint paint) {
29         apply(paint);
30     }
31 
32     private void apply(final Paint paint) {
33         final Typeface oldTypeface = paint.getTypeface();
34         final int oldStyle = oldTypeface != null ? oldTypeface.getStyle() : 0;
35         final int fakeStyle = oldStyle & ~typeface.getStyle();
36         if ((fakeStyle & Typeface.BOLD) != 0) {
37             paint.setFakeBoldText(true);
38         }
39         if ((fakeStyle & Typeface.ITALIC) != 0) {
40             paint.setTextSkewX(-0.25f);
41         }
42         paint.setTypeface(typeface);
43     }
44 
45 }

使用方法也很簡單,以前的TypefaceSpan不是傳family嗎?咱這個傳typeface就能夠了。爲了方便使用,我作了一個單例,由於字體文件在一個程序中會屢次使用,使用的時候放到內存中仍是比較好的,公共類以下:express

 1 package com.justenjoy.util;
 2 
 3 import com.justenjoy.view.MyTypefaceSpan;
 4 
 5 import android.content.Context;
 6 import android.graphics.Typeface;
 7 
 8 /**
 9  * 類名:FontsUtil <br/>
10  * 做者 :王洪賀 <br/>
11  * 描述:獲取自定義字體typefacespan的單例 <br/>
12  * 2015年7月15日
13  */
14 public class FontsUtil {
15 
16     public static FontsUtil fontsUtil;
17 
18     private Context mContext;
19     private static Typeface numTypeface;
20     private static Typeface charTypeface;
21 
22     public FontsUtil(Context context) {
23         this.mContext = context;
24         // 字體資源放在內存中,避免反覆讀取浪費資源
25         numTypeface = Typeface.createFromAsset(mContext.getAssets(),
26                 "fonts/290-CAI978.ttf");
27         charTypeface = Typeface.createFromAsset(mContext.getAssets(),
28                 "fonts/048-CAT978.ttf");
29 
30     }
31 
32     /**
33      * <br/>
34      * 概述:字體單例,避免反覆讀取 <br/>
35      * 
36      * @param context
37      * <br/>
38      * @return
39      */
40     public static FontsUtil getInstance(Context context) {
41         if (fontsUtil == null) {
42             fontsUtil = new FontsUtil(context);
43         }
44         return fontsUtil;
45     }
46 
47     /**
48      * <br/>
49      * 概述:獲取英文字母的字體typefacespan <br/>
50      * 
51      * @param context
52      * <br/>
53      * @return
54      */
55     public MyTypefaceSpan getMyCharTypefaceSpan() {
56         return new MyTypefaceSpan(charTypeface);
57     }
58 
59     /**
60      * <br/>
61      * 概述:獲取數字的字體typefacespan <br/>
62      * 
63      * @param context
64      * <br/>
65      * @return
66      */
67     public MyTypefaceSpan getMyNumTypefaceSpan() {
68         return new MyTypefaceSpan(numTypeface);
69     }
70 
71 }

在spannableString的使用就是:apache

spannableString.setSpan(FontsUtil.getInstance(this).getMyNumTypefaceSpan(), 0, stringsize,Spannable.SPAN_INCLUSIVE_EXCLUSIVE);

其中的兩個字體文件是數字和英文的自定義字體,我就不上傳了。有什麼不明白能夠聯繫個人qq或者郵箱,留言也能夠。app

個人github地址:https://github.com/dongweiq/studyless

歡迎關注,歡迎star o(∩_∩)o 。有什麼問題請郵箱聯繫 dongweiqmail@gmail.com qq714094450ide

相關文章
相關標籤/搜索