How to Use Typefacespan or Stylespan With a Custom Typeface

How can I use TypefaceSpan or StyleSpan with a custom Typeface?

Whilst notme has essentially the right idea, the solution given is a bit hacky as "family" becomes redundant. It is also slightly incorrect because TypefaceSpan is one of the special spans that Android knows about and expects certain behaviour with respect to the ParcelableSpan interface (which notme's subclass does not properly, nor is it possible to, implement).

A simpler and more accurate solution would be:

public class CustomTypefaceSpan extends MetricAffectingSpan
{
private final Typeface typeface;

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

@Override
public void updateDrawState(final TextPaint drawState)
{
apply(drawState);
}

@Override
public void updateMeasureState(final TextPaint paint)
{
apply(paint);
}

private void apply(final Paint paint)
{
final Typeface oldTypeface = paint.getTypeface();
final int oldStyle = oldTypeface != null ? oldTypeface.getStyle() : 0;
final int fakeStyle = oldStyle & ~typeface.getStyle();

if ((fakeStyle & Typeface.BOLD) != 0)
{
paint.setFakeBoldText(true);
}

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

paint.setTypeface(typeface);
}
}

How set Spannable object font with custom font

This is a late answer but will help others to solve the issue.

Use the following code:(I'm using Bangla and Tamil font)

  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);

The outcome is:

Sample Image


CustomTypefaceSpan Class:

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);
}
}

Reference

TextAppearanceSpan with custom fonts

People seem to still have trouble with this so here you go:
This is how it was accomplished for TypefaceSpan, overriding for TextAppearanceSpan is just a tad more code.

Make TextView use a custom typeface with different styles (regular and italic)

After some research I found the following solution for this:

    final Typeface typefaceItalic = Typeface.createFromAsset(getActivity().getAssets(), "customfont-italic.otf");

// there is no easy way in Android to make a single TextView display text using custom typeface with different styles (regular and italic). We need to replace all Italic spans with custom typeface spans for this.
final SpannableString text = new SpannableString("some <i>text</i>");
final StyleSpan[] spans = text.getSpans(0, text.length(), StyleSpan.class);
for (StyleSpan span : spans) {
if (span.getStyle() == Typeface.ITALIC) {
text.setSpan(new CustomTypefaceSpan("customfont", italicTypeface), text.getSpanStart(span), text.getSpanEnd(span), 0);
text.removeSpan(span);
}
}
textView.setText(text);

final Typeface typeface = Typeface.createFromAsset(getActivity().getAssets(), "customfont-regular.otf");
if (typeface != null)
textView.setTypeface(typeface, Typeface.NORMAL);

CustomTypefaceSpan is a class described here: https://stackoverflow.com/a/4826885/190148

How to use support library fonts feature as a part of the TextView content (using spannable)?

Since both answers of MJM and TheMatrix are practically the same (yet over-complex for me) and both were answered around the same time, I couldn't just choose one of them, so I granted +1 for each, asking them to make it shorter yet support XML tag for easier handling with strings file.

For now, here's the much shorter version of how to set a custom font for a part of the text in the TextView:

class CustomTypefaceSpan(private val typeface: Typeface?) : MetricAffectingSpan() {
override fun updateDrawState(paint: TextPaint) {
paint.typeface=typeface
}

override fun updateMeasureState(paint: TextPaint) {
paint.typeface=typeface
}
}

Sample usage :

    val text = "Hello world"
val index = text.indexOf(' ')
val spannable = SpannableStringBuilder(text)
spannable.setSpan(CustomTypefaceSpan(ResourcesCompat.getFont(this, R.font.lato_light)), 0, index, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
spannable.setSpan(CustomTypefaceSpan(ResourcesCompat.getFont(this, R.font.lato_bold)), index, text.length, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
textView.text = spannable

EDIT: seems Google provided a video about this, here :

class CustomTypefaceSpan(val font: Typeface?) : MetricAffectingSpan() {
override fun updateMeasureState(textPaint: TextPaint) = update(textPaint)
override fun updateDrawState(textPaint: TextPaint?) = update(textPaint)

private fun update(tp: TextPaint?) {
tp.apply {
val old = this!!.typeface
val oldStyle = old?.style ?: 0
val font = Typeface.create(font, oldStyle)
typeface = font
}
}
}

And the solution of handling it in strings.xml is also talked about on the video, here , yet using annotations instead of new HTML tags. Example:

strings.xml

<string name="title"><annotation font="lato_light">Hello</annotation> <annotation font="lato_bold">world</annotation></string>

MainActivity.kt

    val titleText = getText(R.string.title) as SpannedString
val spannable = SpannableStringBuilder(titleText)
val annotations = titleText.getSpans(0, titleText.length, android.text.Annotation::class.java)
for (annotation in annotations) {
if(annotation.key=="font"){
val fontName=annotation.value
val typeface= ResourcesCompat.getFont(this@MainActivity,resources.getIdentifier(fontName,"font",packageName))
spannable.setSpan(CustomTypefaceSpan(typeface),spannable.getSpanStart(annotation),spannable.getSpanEnd(annotation), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
textView.text = spannable

And the result:

Sample Image

Still I'm pretty sure it's possible to use fromHtml, but it's probably not worth it.

I also wonder what should be done if we want to use both the basic HTML tags and the cusomzied one we've set for font, if we indeed use annotation there.



Related Topics



Leave a reply



Submit