最近在作車聯網的產品,主打的是語音交互和導航功能,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