¿Cómo puedo utilizar TypefaceSpan o StyleSpan con un tipo de letra personalizado?

Resuelto Philipp Redeker asked hace 54 años • 5 respuestas

No he encontrado una manera de hacer esto. ¿Es posible?

Philipp Redeker avatar Jan 01 '70 08:01 Philipp Redeker
Aceptado

Bueno, no pude descubrir cómo hacerlo con las clases disponibles, así que amplié el método TypefaceSpanpor mi cuenta y ahora me funciona. Aquí esta lo que hice:

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);
    }
}
Philipp Redeker avatar Jan 28 '2011 09:01 Philipp Redeker

Si bien notme tiene esencialmente la idea correcta, la solución dada es un poco complicada ya que "familia" se vuelve redundante. También es ligeramente incorrecto porque TypefaceSpan es uno de los tramos especiales que Android conoce y espera cierto comportamiento con respecto a la interfaz ParcelableSpan (que la subclase de notme no implementa correctamente ni es posible implementar).

Una solución más sencilla y precisa sería:

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);
    }
}
Benjamin Dobell avatar Jul 31 '2013 04:07 Benjamin Dobell