• (原创)如何在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 。有什么问题请邮箱联系 dongweiqmail@gmail.com qq714094450

  • 相关阅读:
    SQLdiag-配置文件-ProfilerCollector
    SQLdiag-配置文件-PerfmonCollector
    SQLdiag-初识
    Trace-跟踪高消耗的语句需添加哪些事件
    RML Utilities for SQL Server
    【译】第十五篇 Integration Services:SSIS参数
    修改数据文件和日志文件路径
    Trace-导出已有的服务器端跟踪
    iphoneX的适配问题
    添加阿里巴巴图标,让你页面小图标都是CSS3写成
  • 原文地址:https://www.cnblogs.com/dongweiq/p/4648085.html
Copyright © 2020-2023  润新知