(原创)如何在spannableString中使用自定义字体

最近在做车联网的产品,主打的是语音交互和导航功能,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, 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行):

我们通过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 <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就可以了。为了方便使用,我做了一个单例,因为字体文件在一个程序中会多次使用,使用的时候放到内存中还是比较好的,公共类如下:

 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的使用就是:

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

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

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

欢迎关注,欢迎star o(∩_∩)o 。有什么问题请邮箱联系 [email protected] qq714094450

时间: 2024-08-27 13:46:49

(原创)如何在spannableString中使用自定义字体的相关文章

Android 中使用自定义字体的方法

1.Android系统默认支持三种字体,分别为:“sans”, “serif”, “monospace 2.在Android中可以引入其他字体 . <?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:Android="http://schemas.android.com/apk/res/android" Android:layout_width="fill

如何在XAF中显示自定义窗体和控件

https://www.devexpress.com/Support/Center/Example/Details/E911 如何在XAF中显示自定义窗体和控件,布布扣,bubuko.com

如何在Axure中使用FontAwesome字体图标

Font Awesome为您提供可缩放的矢量图标,您可以使用CSS所提供的所有特性对它们进行更改,包括:大小.颜色.阴影或者其它任何支持的效果. FontAwesome应用在web网页开发中非常方便,那么在原型设计中是否能使用呢?答案是肯定的,本文将介绍如何在Axure中应用FontAwesome字体. 具体步骤如下 1??.访问 http://fortawesome.github.io/Font-Awesome/  下载最新版本的FontAwesome(当前为4.3),解压下载的压缩文件 2?

如何在AxureRP7中使用FontAwesome字体

我们使用Axure制作原型时,经常会使用到各种小图标.有些朋友自己制作.有些到网上下载,然后使用截图导入到Axure中使用.这样做非常繁琐,有些朋友问Axure是否能够像图像处理工具那样便捷灵活滴使用图标字体呢?答案是:可以!在AxureRP7中使用FontAwesome字体,这是一个非常实用的小技巧,现发布成文与诸君共享. 本文由原型库网站金乌投稿,想系统学习AxureRP7的同学,可以参考金乌老师的AxureRP7网站和APP原型制作从入门到精通视频教程,有20节可以免费试学哦. 第一步:下

iOS中使用自定义字体

1.确定你的项目工程的Resources下有你要用的字体文件(.ttf或者.odf). 2.然后在你的工程的Info.plist文件中新建一行,添加key为:UIAppFonts,类型为Array或Dictionary都行,在UIAppFonts下再建立一个键值对,key为:Item 0,添加Value为XXX.ttf(字体的名字,string型),可以添加多个,使用的时候写对应字体名字就行. 3.在你的项目里要用字体的时候 xx.font = [UIFont fontWithName:@"XX

在自己的iOS程序中引入自定义字体

在网上找了下教程, 大多数都要获取字体文件的真实字体名,用起来比较麻烦. 在iOS7中,引入了UIFontDescriptor,so...可以这么写. UIFontDescriptor *fontdesc = [UIFontDescriptor fontDescriptorWithFontAttributes:@{UIFontDescriptorVisibleNameAttribute : fontName}]; [_richTextView.textStorage addAttributes:

Knative 实战:如何在 Knative 中配置自定义域名及路由规则

作者 |?元毅?阿里云智能事业群高级开发工程师 当前 Knative 中默认支持是基于域名的转发,可以通过域名模板配置后缀,但目前对于用户来说并不能指定全域名设置.另外一个问题就是基于 Path 和 Header 转发的能力,很多情况下我们使用相同的域名,不同服务通过访问路径进行区分. 针对上述这两个问题,我们在阿里云 Knative 中提供了这样的能力,用户可以通过控制台配置自定义域名,并基于 Path 和 Header 进行路由转发设置.如图所示: 自定义域名 登录阿里云容器服务控制台,进入

如何在magento中建立自定义页面

访问url为:http://youip/paypal/standard/help 那么我们反向分析.根据之前的分析,我们找到控制文件\app\code\core\Mage\Paypal\controllers\StandardController.php在里面增加一个方法 public function helpAction() { $this->loadLayout(); $this->_initLayoutMessages('paypal/session'); $this->rend

在ios项目中使用自定义字体

Custom fonts can make all the difference in the world when you're trying to convey a specific user experience. Luckily, it's pretty easy to add your own fonts in your iOS app but there are some common pitfalls to watch out for. Let's walk through how