web-dev-qa-db-fra.com

Comment puis-je utiliser TypefaceSpan ou StyleSpan avec une police de caractères personnalisée?

Je n'ai pas trouvé de moyen de le faire. C'est possible?

71
notme

Eh bien, je ne pouvais pas comprendre comment le faire avec les classes disponibles, j'ai donc étendu le TypefaceSpan par moi-même et maintenant cela fonctionne 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);
    }
}
145
notme

Bien que notme ait essentiellement la bonne idée, la solution proposée est un peu hacky car la "famille" devient superflue. Il est également légèrement incorrect car TypefaceSpan est l'une des plages spéciales que Android connaît et attend certains comportements par rapport à l'interface ParcelableSpan (dont la sous-classe de notme ne fonctionne pas correctement, ni possible, mettre en place).

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);
    }
}
96
Benjamin Dobell

Sur Android P, il est possible d'utiliser la même classe TypefaceSpan que vous connaissez, comme indiqué ici =.

Mais sur les anciennes versions, vous pouvez utiliser ce qu'elles ont montré plus tard dans la vidéo, sur laquelle j'ai écrit ici .

4

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 utilisation: (en 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;  
0
Đonny