如何使用自定义字体设置Spannable对象字体


79

我有一个Spannable对象,我想通过之前加载的自定义字体设置其字体。

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/font_Name.ttf");
Spannable span1 = /*Spannable Item*/;

/// I want to set span1 to have tf font face???
/// Here where I want help.

编辑:
我的问题是我想为文本视图设置两种不同的自定义字体,所以我正在使用Spannable



1
@BenjaminDobell问题不能与答案重复。不要链接到您自己的答案。
乍得宾厄姆

Answers:


212

这是一个较晚的答案,但会帮助其他人解决问题。

使用以下代码:(我使用的是Bangla和Tamil字体)

  TextView txt = (TextView) findViewById(R.id.custom_fonts);  
        txt.setTextSize(30);
        Typeface font = Typeface.createFromAsset(getAssets(), "Akshar.ttf");
        Typeface font2 = Typeface.createFromAsset(getAssets(), "bangla.ttf");   
        SpannableStringBuilder SS = new SpannableStringBuilder("আমারநல்வரவு");
        SS.setSpan (new CustomTypefaceSpan("", font2), 0, 4,Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        SS.setSpan (new CustomTypefaceSpan("", font), 4, 11,Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
        txt.setText(SS);

结果是:

在此处输入图片说明


CustomTypefaceSpan类:

package my.app;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.TypefaceSpan;

public class CustomTypefaceSpan extends TypefaceSpan {

private final Typeface newType;

public CustomTypefaceSpan(String family, Typeface type) {
    super(family);
    newType = type;
}

@Override
public void updateDrawState(TextPaint ds) {
    applyCustomTypeFace(ds, newType);
}

@Override
public void updateMeasureState(TextPaint paint) {
    applyCustomTypeFace(paint, newType);
}

private static void applyCustomTypeFace(Paint paint, Typeface tf) {
    int oldStyle;
    Typeface old = paint.getTypeface();
    if (old == null) {
        oldStyle = 0;
    } else {
        oldStyle = old.getStyle();
    }

    int fake = oldStyle & ~tf.getStyle();
    if ((fake & Typeface.BOLD) != 0) {
        paint.setFakeBoldText(true);
    }

    if ((fake & Typeface.ITALIC) != 0) {
        paint.setTextSkewX(-0.25f);
    }

    paint.setTypeface(tf);
}
}

参考


11
不错的一个方法-尽管如果要与族“”一起使用它,为什么不从构造函数中完全删除family参数,而只需调用super(“”);即可。
亚当

@ imran-rana我怎么用CustomTypefaceSpan
mahdi pishguy

@Imran Rana,此自定义类给出了一个皮棉错误。“此类实现Parcelable,但不提供CREATOR字段。”
Krups

@Krups是的,如果CustomTypefaceSpan由操作系统打包和不打包,则将无法正常工作。
alexbirkett

警告:此类实现Parcelable但不提供CREATOR字段。
Mir-Ismaili

24

创建一个CustomTypefaceSpan类:

import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;

public class CustomTypefaceSpan extends MetricAffectingSpan {

    private final Typeface typeface;

    public CustomTypefaceSpan(Typeface typeface) {
        this.typeface = typeface;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        applyCustomTypeFace(ds, typeface);
    }

    @Override
    public void updateMeasureState(TextPaint paint) {
        applyCustomTypeFace(paint, typeface);
    }

    private static void applyCustomTypeFace(Paint paint, Typeface tf) {
        paint.setTypeface(tf);
    }
}

与Android框架跨越类的使用方式相同:

    TextView textView = (TextView) findViewById(R.id.custom_fonts);
    Typeface font = Typeface.createFromAsset(getAssets(), "Akshar.ttf");
    Typeface font2 = Typeface.createFromAsset(getAssets(), "bangla.ttf");
    SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("আমারநல்வரவு");
    spannableStringBuilder.setSpan (new CustomTypefaceSpan(font2), 0, 4,Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    spannableStringBuilder.setSpan (new CustomTypefaceSpan(font), 4, 11,Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
    textView.setText(spannableStringBuilder);

该答案基于Imran Rana的答案,但没有扩展TypefaceSpan,然后禁用了其功能。直接CustomTypefaceSpan延伸MetricAffectingSpan

该答案与Imran Rana的答案存在缺陷。跨度未取消。即,如果您这样做(kotlin):

    val parcel = Parcel.obtain()
    TextUtils.writeToParcel(spannableStringBuilder, parcel, 0)
    parcel.setDataPosition(0)
    val sequence = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel)
    parcel.recycle()

CustomTypefaceSpan设置的任何对象spannableStringBuilder都不会进行编组和解组。


21

我们不需要使用CustomTypefaceSpan。这是使用StyleSpan的解决方案。

/**
* setCustomFontTypeSpan
* @param context
* @param source
* @param startIndex
* @param endIndex
* @param font
* @return
*/
public static SpannableString setCustomFontTypeSpan(Context context, String 
source, int startIndex, int endIndex, int font) {
      final SpannableString spannableString = new SpannableString(source);
      Typeface typeface = ResourcesCompat.getFont(context, font);
      spannableString.setSpan(new StyleSpan(typeface.getStyle()), 
      startIndex,endIndex,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableString;
}

String source = "Hello world";
SpannableString string = setCustomFontTypeSpan(context, source, 6, 
source.length(), R.font.open_sans_bold);
textView.setText(string);

2
StyleSpan不能设置typeFace。正如文档中所述:跨度允许设置其附加文本的样式。可能的样式为:Typeface#NORMAL,Typeface#BOLD,Typeface#ITALIC和Typeface#BOLD_ITALIC。给定的代码会将span设置为BOLD,不影响字体
kza

13

如果您使用的是Roboto,则可以在构造函数中设置其他TypefaceSpan

TypefaceSpan typefaceSpan = new TypefaceSpan("sans-serif-medium");

textView.setSpan(typefaceSpan, indexStart, textLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

2

在科特林将是:

第一步,创建此类

class CustomTypefaceSpan(family: String?, private val newType: Typeface) :
  TypefaceSpan(family) {
  override fun updateDrawState(ds: TextPaint) {
      applyCustomTypeFace(ds, newType)
  }

  override fun updateMeasureState(paint: TextPaint) {
      applyCustomTypeFace(paint, newType)
  }

  companion object {
      private fun applyCustomTypeFace(paint: Paint, tf: Typeface) {
          val oldStyle: Int
          val old = paint.typeface
          oldStyle = old?.style ?: 0
          val fake = oldStyle and tf.style.inv()
          if (fake and Typeface.BOLD != 0) {
              paint.isFakeBoldText = true
          }
          if (fake and Typeface.ITALIC != 0) {
              paint.textSkewX = -0.25f
          }
          paint.typeface = tf
      }
  }

}

第二步

    val prefixText = SpannableString("I read and accept ")
    val prefixTextLen = prefixText.length

    prefixText.setSpan(
        CustomTypefaceSpan("", ResourcesCompat.getFont(context, R.font.gotham_bold)!!),
        0,
        prefixTextLen,
        0
    )

2

> = API 28的更新,更简单的答案

val myTypeface = Typeface.create(ResourcesCompat.getFont(context, R.font.acme), Typeface.NORMAL)
val string = SpannableString("Text with typeface span.")
string.setSpan(TypefaceSpan(myTypeface), 10, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
string.setSpan(TypefaceSpan("monospace"), 19, 22, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

textView.text = string

1

请尽量把设置Spannable你的TextView第一,然后尝试字样分配给您的TextView使用myTextView.setTypeface(tf);


除了Serkan的答案,我还在blog.stylingandroid.com/archives/177上写了一个博客条目,其中详细介绍了如何使用跨度。它没有专门介绍设置字体,这就是为什么我没有将其作为答案发布的原因,但是它的确涵盖了一些普遍使用跨距的常见陷阱。
Mark Allison

但这只是在整个TextView上设置字体吗?这不是跨度。
alexbirkett

-1

这是一个示例,其中str是您的完整字符串,而boldString是需要将其变为粗体的部分。

public static SpannableString getTextStyleSpan(String str, String boldString) {

        SpannableString formated = new SpannableString(str);

        int start1 = str.indexOf(boldString);
        int end1 = start1 + colorString1.length();

        formated.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD), start1, end1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
        return formated;
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.