Cómo configurar la fuente de objeto Spannable con fuente personalizada

80

Tengo un objeto Spannable que quiero configurar su fuente mediante una fuente personalizada que he cargado antes.

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.

EDITAR:
Mi problema es que quiero configurar dos fuentes personalizadas diferentes para la vista de texto, así que estoy trabajando con Spannable

Mohamedghonemi
fuente
Duplicado de stackoverflow.com/questions/4819049/…
Benjamin Dobell
1
@BenjaminDobell Una pregunta no puede ser un duplicado de una respuesta. No vincule su propia respuesta.
Chad Bingham

Respuestas:

217

Esta es una respuesta tardía, pero ayudará a otros a resolver el problema.

Use el siguiente código: (estoy usando la fuente bengalí y 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);

El resultado es:

ingrese la descripción de la imagen aquí


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

Referencia

Imran Rana
fuente
11
Bonito, aunque si lo va a usar con la familia "", ¿por qué no eliminar el parámetro de la familia del constructor por completo y simplemente llamar a super ("");
Adam
@ imran-rana, ¿cómo puedo usarlo CustomTypefaceSpan?
mahdi pishguy
@Imran Rana, esta clase personalizada da un error de pelusa. "Esta clase implementa Parcelable pero no proporciona un campo CREATOR".
Krups
@Krups Sí, esto no va a funcionar si CustomTypefaceSpan es parcelado y no parcelado por el sistema operativo.
alexbirkett
Advertencia: esta clase implementa Parcelablepero no proporciona un CREATORcampo.
Mir-Ismaili
24

Cree una clase 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);
    }
}

Úselo de la misma manera que el marco de Android abarca clases:

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

Esta respuesta se basa en la respuesta de Imran Rana, pero no se extiende TypefaceSpany luego desactiva su funcionalidad. CustomTypefaceSpanse extiende MetricAffectingSpandirectamente.

Esta respuesta comparte un defecto con la respuesta de Imran Rana. El tramo no está parcelado. Es decir, si haces esto (kotlin):

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

Cualquier CustomTypefaceSpanobjeto colocado en spannableStringBuilderno será ordenado ni desordenado.

alexbirkett
fuente
21

No necesitamos utilizar CustomTypefaceSpan. Aquí está la solución con 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);
Himanshu
fuente
3
StyleSpan no está diseñado para establecer typeFace. Como se indica en la documentación: Span que permite establecer el estilo del texto al que se adjunta. Los estilos posibles son: Tipo de letra # NORMAL, Tipo de letra # BOLD, Tipo de letra # ITALIC y Tipo de letra # BOLD_ITALIC. El código dado establecería span en BOLD, sin afectar el tipo de letra
kza
14

Si está utilizando Roboto, puede establecer un TypefaceSpan diferente en el constructor

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

textView.setSpan(typefaceSpan, indexStart, textLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Renan Nery
fuente
3

Respuesta más nueva y sencilla para> = 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
Shalbert
fuente
2

En kotlin estaría:

Primer paso , crea esta clase

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

}

Segundo paso ,

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

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

Trate de establecer su Spannableen su TextViewprimero y luego, intente asignar el tipo de letra a su TextViewcon myTextView.setTypeface(tf);

serkanozel
fuente
Además de la respuesta de Serkan, escribí una entrada de blog que detalla cómo usar los intervalos en blog.stylingandroid.com/archives/177 . No cubre específicamente la configuración de tipos de letra, razón por la cual no he publicado esto como respuesta, pero sí cubre algunos de los errores comunes con los intervalos en general.
Mark Allison
¿Pero esto solo establece el tipo de letra en todo TextView? No es un lapso.
alexbirkett
0

Si está utilizando Android KTX buildSpannable{...},

Recomiendo este.

inline fun SpannableStringBuilder.font(typeface: Typeface? = null, builderAction: SpannableStringBuilder.() -> Unit) =
    inSpans(StyleSpan(typeface?.style ?: Typeface.DEFAULT.style), builderAction = builderAction)

Uso

binding.title.text = buildSpannedString {
    color(getColor(R.color.main_mint)) {
        font(getFont(R.font.notosans_medium)) {
            append("colored and typefaced")
        }
    }
}
Estudio MJ
fuente
-1

Aquí hay un ejemplo en el que str es su cadena completa y boldString es la parte que necesita poner en negrita.

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;
    }
Max Droid
fuente