zoukankan      html  css  js  c++  java
  • (原创)如何在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

  • 相关阅读:
    array and ram
    char as int
    pointer of 2d array and address
    Install SAP HANA EXPRESS on Google Cloud Platform
    Ubuntu remount hard drive
    Compile OpenSSL with Visual Studio 2019
    Install Jupyter notebook and tensorflow on Ubuntu 18.04
    Build OpenCV text(OCR) module on windows with Visual Studio 2019
    Reinstall VirtualBox 6.0 on Ubuntu 18.04
    Pitfall in std::vector<cv::Mat>
  • 原文地址:https://www.cnblogs.com/dongweiq/p/4648085.html
Copyright © 2011-2022 走看看