Je n'ai pas trouvé de moyen de le faire. Est-ce possible ?
@notme qu'est-ce que je dois passer à la variable chaîne famille dans ce constructeur CustomTypefaceSpan(String family, Typeface type) {} ? ???
Je n'ai pas trouvé de moyen de le faire. Est-ce possible ?
Comme je n'arrivais pas à trouver comment le faire avec les classes disponibles, j'ai étendu la fonction TypefaceSpan
par moi-même et maintenant ça marche pour moi. Voici ce que j'ai fait :
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);
}
}
Bien que notme ait essentiellement la bonne idée, la solution donnée est un peu bancale car "famille" devient redondant. Elle est également légèrement incorrecte car TypefaceSpan est l'un des espaces spéciaux qu'Android connaît et attend un certain comportement par rapport à l'interface ParcelableSpan (que la sous-classe de notme n'implémente pas correctement, et qu'il n'est pas possible d'implémenter).
Une solution plus simple et plus précise serait :
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);
}
}
@MarcoW et @Benjamin .... Benjamin dit que vous ne pouvez pas utiliser TypefaceSpan
mais ensuite Marco montre un exemple de travail en utilisant juste ça. Lequel est le bon ? Benjamin a testé ton exemple ?
@JaysonMinard Je pense que @MarcoW a commenté la mauvaise réponse. Je suppose qu'il voulait commenter la réponse de @notme, puisque c'est sa classe qu'il a utilisée. Pour être clair, je ne suis pas en train de dire que vous ne peut pas sous-classe TypefaceSpan
. Je suis juste en train de suggérer très fortement tu ne devrais pas . Ce faisant, vous violez le principe de substitution de Liscov et c'est une très mauvaise pratique. Vous avez sous-classé une classe qui spécifie la police de caractères par le biais d'une balise family
nom y est parcellisable ; vous avez alors totalement écrasé ce comportement et fait de la family
paramètre confus et inutile, et le Span
est également no morcelable.
Peut-être cette réponse peut être utile .
Je vais ajouter mon approche simple pour la cohérence. Je ne sais pas pourquoi deux des réponses ci-dessus sont longues :)
SpannableString sb = new SpannableString(getResources().getString(R.string.subtitle));
sb.setSpan(new TypefaceSpan("sans-serif-light"), 9, 15, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
sb.setSpan(new TypefaceSpan("sans-serif-light"), 24, 34, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
textView.setText(sb);
Explication, parce que j'ai trouvé les Docs délicats :
La magie ici est SPAN_EXCLUSIVE_INCLUSIVE
avec lequel vous pouvez ajouter la même police de caractères sur différentes parties de la chaîne.
Ce qui précède fonctionne également avec SpannableStringBuilder
si vous souhaitez ajouter (ajouter) du texte ou le modifier.
Veillez à expérimenter avec les drapeaux .
Pour les différentes portées, voir exemple ici .
Si quelqu'un est intéressé, voici la version C# Xamarin du code de Benjamin :
using System;
using Android.Graphics;
using Android.Text;
using Android.Text.Style;
namespace Utils
{
//https://stackoverflow.com/a/17961854/1996780
/// <summary>A text span which applies <see cref="Android.Graphics.Typeface"/> on text</summary>
internal class CustomFontSpan : MetricAffectingSpan
{
/// <summary>The typeface to apply</summary>
public Typeface Typeface { get; }
/// <summary>CTor - creates a new instance of the <see cref="CustomFontSpan"/> class</summary>
/// <param name="typeface">Typeface to apply</param>
/// <exception cref="ArgumentNullException"><paramref name="typeface"/> is null</exception>
public CustomFontSpan(Typeface typeface) =>
Typeface = typeface ?? throw new ArgumentNullException(nameof(typeface));
public override void UpdateDrawState(TextPaint drawState) => Apply(drawState);
public override void UpdateMeasureState(TextPaint paint) => Apply(paint);
/// <summary>Applies <see cref="Typeface"/></summary>
/// <param name="paint"><see cref="Paint"/> to apply <see cref="Typeface"/> on</param>
private void Apply(Paint paint)
{
Typeface oldTypeface = paint.Typeface;
var oldStyle = oldTypeface != null ? oldTypeface.Style : 0;
var fakeStyle = oldStyle & Typeface.Style;
if (fakeStyle.HasFlag(TypefaceStyle.Bold))
paint.FakeBoldText = true;
if (fakeStyle.HasFlag(TypefaceStyle.Italic))
paint.TextSkewX = -0.25f;
paint.SetTypeface(Typeface);
}
}
}
Et l'usage : (dans l'activité OnCreate)
var txwLogo = FindViewById<TextView>(Resource.Id.logo);
var font = Resources.GetFont(Resource.Font.myFont);
var wordtoSpan = new SpannableString(txwLogo.Text);
wordtoSpan.SetSpan(new CustomFontSpan(font), 6, 7, SpanTypes.InclusiveInclusive); //One caracter
txwLogo.TextFormatted = wordtoSpan;
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.