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

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


Well I couldn't figure out how to do it with the available classes so I extended the TypefaceSpan on my own an now it works for me. Here is what I did:

package de.myproject.text.style;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);    }}


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


On Android P it's possible using the same TypefaceSpan class you know of, as shown here.

But on older versions, you can use what they've shown later in the video, which I've written about here.