博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(原创)如何在spannableString中使用自定义字体
阅读量:7241 次
发布时间:2019-06-29

本文共 6660 字,大约阅读时间需要 22 分钟。

最近在做车联网的产品,主打的是语音交互和导航功能,UI给的导航界面可真是够酷炫的。但麻烦的事情也来了,里面的一句话居然用到了三种字体。界面如图所示:

从图中可以看出 500m左前方行驶 居然使用了三种字体,数字一种、英文一种、汉字一种,(这里不讨论拆分三个textview能不能实现的问题,如果能实现也是最迫不得已的办法,何况你解决了这个,上面那个 -2h30m 你要拆成4个textview吗?显然这不合理)我们知道spannableString是个 很强大的类,可以通过new typefacespan(family)设置字体,但他们支持的是系统的三种字体,但我还从没有使用过自定义的字体。为了解决这个问题我仔细看了关于spannableString的介绍。然而这类文章真的不多,只是从一篇文章中得知可以通过自定义typefacespan来使用自定义字体。(文章地址:http://www.cnblogs.com/jisheng/archive/2013/01/10/2854088.html)

如何自定义typefacespan,这东西也没别人做过先例,无奈只好自己去看源码:

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, software11  * 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 and14  * 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 include34      * "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     @Override64     public void updateDrawState(TextPaint ds) {65         apply(ds, mFamily);66     }67 68     @Override69     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行):

我们通过Typeface.create(family,oldStyle)得到了一个typeface,然后从86~92行是设置粗体和斜体。也就是说这个地方才是设置字体的真谛。而我们知道可以通过读取文件的方式得到自定义的typeface,因此完全可以通过掉包的方式实现自定义字体。于是我仿照Typefacespan实现了自己的一个MyTypefaceSpan的类,如下:

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 
10 * 作者 :王洪贺
11 * 描述:
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 @Override23 public void updateDrawState(final TextPaint drawState) {24 apply(drawState);25 }26 27 @Override28 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就可以了。为了方便使用,我做了一个单例,因为字体文件在一个程序中会多次使用,使用的时候放到内存中还是比较好的,公共类如下:

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 
10 * 作者 :王洪贺
11 * 描述:获取自定义字体typefacespan的单例
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 *
34 * 概述:字体单例,避免反复读取
35 * 36 * @param context37 *
38 * @return39 */40 public static FontsUtil getInstance(Context context) {41 if (fontsUtil == null) {42 fontsUtil = new FontsUtil(context);43 }44 return fontsUtil;45 }46 47 /**48 *
49 * 概述:获取英文字母的字体typefacespan
50 * 51 * @param context52 *
53 * @return54 */55 public MyTypefaceSpan getMyCharTypefaceSpan() {56 return new MyTypefaceSpan(charTypeface);57 }58 59 /**60 *
61 * 概述:获取数字的字体typefacespan
62 * 63 * @param context64 *
65 * @return66 */67 public MyTypefaceSpan getMyNumTypefaceSpan() {68 return new MyTypefaceSpan(numTypeface);69 }70 71 }

在spannableString的使用就是:

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

其中的两个字体文件是数字和英文的自定义字体,我就不上传了。有什么不明白可以联系我的qq或者邮箱,留言也可以。

我的github地址:https://github.com/dongweiq/study

欢迎关注,欢迎star o(∩_∩)o 。有什么问题请邮箱联系 dongweiqmail@gmail.com qq714094450

 

你可能感兴趣的文章
C语言移位
查看>>
深度了解git工具
查看>>
Integer cache -127 - 128
查看>>
如何拷贝一个wchar_t类型的字符串
查看>>
设计模式(观察者模式)
查看>>
对Promise中的resolve,reject,catch的理解
查看>>
NFS挂载异常 mount.nfs: Input/output error
查看>>
爬虫 Day03
查看>>
内存池的原理及实现
查看>>
phpqrcode生成动态二维码简单实例
查看>>
python-函数
查看>>
Scrapy反爬
查看>>
(十三) 整合spring cloud云架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)
查看>>
Java-日历表
查看>>
GLPaint in OpenGL ES 2.0
查看>>
CocoaAsyncSocket学习
查看>>
关于form.item不兼容的问题
查看>>
poj Supermarket
查看>>
常用变量的获取
查看>>
洛谷9月月赛round2
查看>>