Utilizzo di caratteri personalizzati in TextView Android utilizzando xml


92

Ho aggiunto un file di carattere personalizzato alla mia cartella risorse / caratteri. Come lo uso dal mio XML?

Posso usarlo dal codice come segue:

TextView text = (TextView) findViewById(R.id.textview03);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf");
text.setTypeface(tf);

Non posso farlo da XML usando un android:typeface="/fonts/Molot.otf"attributo?


Ho cercato molto e non c'è modo che tu possa farlo da xml.
Cd

2
provare a controllare questo post stackoverflow.com/questions/2376250/...
dor506

Dai un'occhiata a questa risposta ! Ti consente di utilizzare più caratteri e di utilizzare XML.
Rafa0809

Come altri hanno detto di seguito, puoi usare Calligraphy per ottenere questo risultato.
mbonnin

Controlla questo articolo gadgetsaint.com/tips/…
ASP

Risposte:


45

Risposta breve: No. Android non ha il supporto integrato per l'applicazione di caratteri personalizzati ai widget di testo tramite XML.

Tuttavia, c'è una soluzione alternativa che non è particolarmente difficile da implementare.

Primo

Dovrai definire il tuo stile. Nella tua cartella / res / values, apri / crea il file attrs.xml e aggiungi un oggetto dichiarabile in questo modo:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FontText">
        <attr name="typefaceAsset" format="string"/>
    </declare-styleable>
</resources>

Secondo

Supponendo che tu voglia usare spesso questo widget, dovresti impostare una semplice cache per gli Typefaceoggetti caricati , poiché caricarli dalla memoria al volo può richiedere tempo. Qualcosa di simile a:

public class FontManager {
    private static FontManager instance;

    private AssetManager mgr;

    private Map<String, Typeface> fonts;

    private FontManager(AssetManager _mgr) {
        mgr = _mgr;
        fonts = new HashMap<String, Typeface>();
    }

    public static void init(AssetManager mgr) {
        instance = new FontManager(mgr);
    }

    public static FontManager getInstance() {
        if (instance == null) {
            // App.getContext() is just one way to get a Context here
            // getContext() is just a method in an Application subclass
            // that returns the application context
            AssetManager assetManager = App.getContext().getAssets();
            init(assetManager);
        }
        return instance;
    }

    public Typeface getFont(String asset) {
        if (fonts.containsKey(asset))
            return fonts.get(asset);

        Typeface font = null;

        try {
            font = Typeface.createFromAsset(mgr, asset);
            fonts.put(asset, font);
        } catch (Exception e) {

        }

        if (font == null) {
            try {
                String fixedAsset = fixAssetFilename(asset);
                font = Typeface.createFromAsset(mgr, fixedAsset);
                fonts.put(asset, font);
                fonts.put(fixedAsset, font);
            } catch (Exception e) {

            }
        }

        return font;
    }

    private String fixAssetFilename(String asset) {
        // Empty font filename?
        // Just return it. We can't help.
        if (TextUtils.isEmpty(asset))
            return asset;

        // Make sure that the font ends in '.ttf' or '.ttc'
        if ((!asset.endsWith(".ttf")) && (!asset.endsWith(".ttc")))
            asset = String.format("%s.ttf", asset);

        return asset;
    }
}

Questo ti consentirà di utilizzare estensioni di file .ttc, ma non è stato testato.

Terzo

Crea una nuova classe di sottoclassi TextView. Questo particolare esempio prende in considerazione il tipo di carattere XML definito ( bold, italic, etc.) e applicarlo al font (supponendo che si sta utilizzando un file .ttc).

/**
 * TextView subclass which allows the user to define a truetype font file to use as the view's typeface.
 */
public class FontText extends TextView {
    public FontText(Context context) {
        this(context, null);
    }

    public FontText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FontText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        if (isInEditMode())
            return;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FontText);

        if (ta != null) {
            String fontAsset = ta.getString(R.styleable.FontText_typefaceAsset);

            if (!TextUtils.isEmpty(fontAsset)) {
                Typeface tf = FontManager.getInstance().getFont(fontAsset);
                int style = Typeface.NORMAL;
                float size = getTextSize();

                if (getTypeface() != null)
                    style = getTypeface().getStyle();

                if (tf != null)
                    setTypeface(tf, style);
                else
                    Log.d("FontText", String.format("Could not create a font from asset: %s", fontAsset));
            }
        }
    }
}

Finalmente

Sostituisci le istanze di TextViewnel tuo XML con il nome completo della classe. Dichiara il tuo spazio dei nomi personalizzato proprio come faresti con lo spazio dei nomi Android. Notare che "typefaceAsset" dovrebbe puntare a un file .ttf o .ttc contenuto nella directory / assets.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.FontText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a custom font text"
        custom:typefaceAsset="fonts/AvenirNext-Regular.ttf"/>
</RelativeLayout>

Bella risposta! Una domanda però: perché sei tornato quando isInEditMode?
Avi Shukron

04-11 18: 18: 32.685 3506-3506 / com.example.demo E / AndroidRuntime ﹕ ECCEZIONE FATALE: processo principale: com.example.demo, PID: 3506 android.view.InflateException: riga file XML binario n. 2: errore inflating class com.example.demo.libraries.LatoTextView su android.view.LayoutInflater.createView (LayoutInflater.java:620) su android.view.LayoutInflater.createViewFromTag (LayoutInflater.java:696) su android.view.LayoutInflater.inflate ( LayoutInflater.java:469) su android.view.LayoutInflater.inflate (LayoutInflater.java:397) su ...
e-info128

@AvrahamShukron - È lì perché ho continuato a ricevere un errore in Android Studio mentre ero in modalità di anteprima (presumibilmente perché non sa come gestire l'applicazione di un carattere personalizzato.
themarshal

Aggiunto xmlns: custom = " schemas.android.com/tools " in RelativeLayout e l'errore era sparito. Grazie amico
Naveed Ahmad il

1
Ciao @themarshal: invece di xmlns: custom = " schemas.android.com/tools " dovresti usare: xmlns: custom = " schemas.android.com/apk/res-auto " per usare attributi stilizzabili.
Abhinav Saxena

28

Ecco un esempio di codice che esegue questa operazione. Ho il carattere definito in una variabile finale statica e il file del carattere si trova nella directory degli asset.

public class TextViewWithFont extends TextView {

    public TextViewWithFont(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context) {
        super(context);
        this.setTypeface(MainActivity.typeface);
    }

}

5
L'OP afferma specificamente che sa come impostare il font in modo programmatico (fornisce anche un esempio). La domanda è come impostare il carattere in xml?
SMBiggs

13

Crea il tuo TextView personalizzato che appartiene al carattere che desideri utilizzare. In questa classe, utilizzo un campo mTypeface statico per memorizzare nella cache il carattere tipografico (per prestazioni migliori)

public class HeliVnTextView extends TextView {

/*
 * Caches typefaces based on their file path and name, so that they don't have to be created every time when they are referenced.
 */
private static Typeface mTypeface;

public HeliVnTextView(final Context context) {
    this(context, null);
}

public HeliVnTextView(final Context context, final AttributeSet attrs) {
    this(context, attrs, 0);
}

public HeliVnTextView(final Context context, final AttributeSet attrs, final int defStyle) {
    super(context, attrs, defStyle);

     if (mTypeface == null) {
         mTypeface = Typeface.createFromAsset(context.getAssets(), "HelveticaiDesignVnLt.ttf");
     }
     setTypeface(mTypeface);
}

}

Nel file xml:

<java.example.HeliVnTextView
        android:id="@+id/textView1"
        android:layout_width="0dp"
        ... />

Nella classe Java:

HeliVnTextView title = new HeliVnTextView(getActivity());
title.setText(issue.getName());

11

L'attività implementa LayoutInflater.Factory2 che fornisce callback su ogni vista creata. È possibile applicare uno stile al TextView con l'attributo Family di font personalizzato, caricare i caratteri tipografici su richiesta e chiamare setTypeface automaticamente nelle viste di testo istanziate.

Sfortunatamente, a causa della relazione architettonica delle istanze Inflater relative ad Attività e Windows, l'approccio più semplice per utilizzare i caratteri personalizzati in Android è memorizzare nella cache i caratteri caricati a livello di applicazione.

Il codice di esempio di base è qui:

https://github.com/leok7v/android-textview-custom-fonts

  <style name="Baroque" parent="@android:style/TextAppearance.Medium">
    <item name="android:layout_width">fill_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:textColor">#F2BAD0</item>
    <item name="android:textSize">14pt</item>
    <item name="fontFamily">baroque_script</item>
  </style>

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:custom="http://schemas.android.com/apk/res/custom.fonts"
          android:orientation="vertical"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
  >
  <TextView
    style="@style/Baroque"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/sample_text"
  />

risultati in

inserisci qui la descrizione dell'immagine


Non ho toccato quel codice per 2 anni. Ma dovrebbe. Non vedo nulla in teoria che lo impedisca.
Leone

7

Non è una buona idea usare caratteri personalizzati in xml a causa di questo fatto che devi farlo a livello di programmazione per evitare la perdita di memoria!


6
Sembra che la perdita di memoria sia stata risolta in Ice Cream Sandwich.
Michael Scheper

2
È necessario utilizzare il metodo TypedArray recycle () per evitare perdite di memoria.
Abhinav Saxena

7

AGGIORNAMENTO: https://github.com/chrisjenx/Calligraphy sembra essere una soluzione superiore a questo.


Forse puoi usare la riflessione per iniettare / hackerare il tuo carattere nell'elenco statico dei caratteri disponibili quando viene creata la tua applicazione? Sono interessato al feedback degli altri se questa è un'idea davvero, davvero pessima o se questa è un'ottima soluzione - sembra che sarà uno di quegli estremi ...

Sono stato in grado di inserire il mio carattere tipografico personalizzato nell'elenco dei caratteri tipografici di sistema con il mio nome di famiglia di caratteri, quindi specificando quel nome di famiglia di caratteri personalizzato ("brush-script") come valore di Android: FontFamily su un TextView standard funzionava sul mio LG G4 con Android 6.0.

public class MyApplication extends android.app.Application
{
    @Override
    public void onCreate()
    {
        super.onCreate();

        Typeface font = Typeface.createFromAsset(this.getResources().getAssets(),"fonts/brush-script.ttf");
        injectTypeface("brush-script", font);
    }

    private boolean injectTypeface(String fontFamily, Typeface typeface)
    {
        try
        {
            Field field = Typeface.class.getDeclaredField("sSystemFontMap");
            field.setAccessible(true);
            Object fieldValue = field.get(null);
            Map<String, Typeface> map = (Map<String, Typeface>) fieldValue;
            map.put(fontFamily, typeface);
            return true;
        }
        catch (Exception e)
        {
            Log.e("Font-Injection", "Failed to inject typeface.", e);
        }
        return false;
    }
}

Nel mio layout

<TextView
    android:id="@+id/name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Fancy Text"
    android:fontFamily="brush-script"/>

Non funziona per me, puoi fornire maggiori dettagli su come usarlo? La MyApplicationclasse deve essere chiamata?
Dadan

@Yawz dovresti chiamare il metodo injectTypeface almeno una volta nella tua applicazione. Se registra un'eccezione sarei interessato ai dettagli. L'ho provato solo sul mio LG G4 con Android 6.0 (stavo facendo alcune delle mie ricerche in quel momento) e mi aspetto che non funzioni su tutte le versioni di Android.
Ross Bradbury

@RossBradbury non funziona su alcuni dispositivi .. la maggior parte dei dispositivi funziona correttamente ma alcuni dispositivi non accettano questa famiglia di caratteri .. il mio dispositivo testato - modello lenova a7000
Ranjith Kumar

AGGIORNAMENTO: github.com/chrisjenx/Calligraphy è una soluzione superiore.
Ross Bradbury

4

Crea una cartella dei caratteri nelle risorse e aggiungi tutti i caratteri richiesti lì.

public class CustomTextView extends TextView {
    private static final String TAG = "TextView";

    public CustomTextView(Context context) {
        super(context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }

    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        String customFont = a.getString(R.styleable.CustomTextView_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String fontName) {
        Typeface typeface = null;
        try {
            if(fontName == null){
                fontName = Constants.DEFAULT_FONT_NAME;
            }
            typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/" + fontName);
        } catch (Exception e) {
            Log.e(TAG, "Unable to load typeface: "+e.getMessage());
            return false;
        }
        setTypeface(typeface);
        return true;
    }
}

e aggiungi un dichiarabile in attrs.xml

<declare-styleable name="CustomTextView">
      <attr name="customFont" format="string"/>
</declare-styleable>

e quindi aggiungi il tuo customFont come

app:customFont="arial.ttf"

puoi anche personalizzare la classe sopra per lavorare con lo stile come fatto qui. github.com/leok7v/android-textview-custom-fonts/blob/master/res/…
AndroidGeek

4

So che questa è una vecchia domanda, ma ho trovato una soluzione molto più semplice.

Prima dichiara il tuo TextView in xml come al solito. Metti il ​​tuo carattere (TTF o TTC) nella cartella delle risorse

app \ src \ main \ assets \

Quindi imposta il carattere tipografico per la visualizzazione del testo nel tuo metodo onCreate.

@Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_name);    

    TextView textView = findViewById(R.id.my_textView);
    Typeface typeface = Typeface.createFromAsset(getAssets(), "fontName.ttf");
    textView.setTypeface(typeface);
}

Fatto.


1
La domanda afferma chiaramente di usarlo all'interno di file xml non in modo programmatico
Gustavo Baiocchi Costa


0

invece di xmlns: custom = "schemas.android.com/tools"; dovresti usare: xmlns: custom = "schemas.android.com/apk/res-auto"; per utilizzare attributi stilizzabili. Ho apportato questa modifica e ora funziona.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.