Utilizzo di un carattere tipografico personalizzato in Android


111

Voglio usare un carattere personalizzato per la mia applicazione Android che sto creando.
Posso cambiare individualmente il carattere tipografico di ogni oggetto da Code, ma ne ho centinaia.

Così,

  • C'è un modo per farlo dall'XML? [Impostazione di un carattere tipografico personalizzato]
  • C'è un modo per farlo dal codice in un posto, per dire che l'intera applicazione e tutti i componenti dovrebbero usare il carattere tipografico personalizzato invece di quello predefinito?

stackoverflow.com/questions/5541058/… Guarda questo post Ho pubblicato il codice completo qui riguardo a questo problema
Manish Singla

È possibile utilizzare variabili statiche nella propria attività principale per contenere i riferimenti ai caratteri incorporati. Ciò causerebbe la presenza di un set persistente di caratteri che non verrà rilevato da GC.
Jacksonkr

Metodo di fabbrica. O un metodo che prende la tua vista e imposta tutte le impostazioni di font e caratteri tipografici.
mtmurdock

La nuova libreria di supporto 26 ora consente di utilizzare i caratteri in XML. Ecco come fare i caratteri in XML
Vinicius Silva

Risposte:


80

C'è un modo per farlo dall'XML?

No scusa. È possibile specificare solo i caratteri tipografici incorporati tramite XML.

C'è un modo per farlo dal codice in un posto, per dire che l'intera applicazione e tutti i componenti dovrebbero usare il carattere tipografico personalizzato invece di quello predefinito?

Non che io sappia.

Al giorno d'oggi ci sono una varietà di opzioni per questi:

  • Risorse dei caratteri e backport nell'SDK di Android, se utilizzi appcompat

  • Librerie di terze parti per coloro che non utilizzano appcompat, sebbene non tutte supporteranno la definizione del carattere nelle risorse di layout


4
@Codevalley: Beh, per molti versi, la risposta migliore è non agitarsi con i caratteri personalizzati. Tendono ad essere grandi, aumentando i download e riducendo il numero di persone che scaricheranno e continueranno a utilizzare la tua app.
CommonsWare

22
@CommonsWare: non sono necessariamente d'accordo. Il carattere tipografico è parte integrante dello stile dell'interfaccia utente come si fa con le immagini di sfondo, ecc. E le dimensioni non sono sempre necessariamente grandi. Ad esempio, il carattere nel mio caso è di soli 19,6 KB :)
Codevalley

2
@Amit: non sono state apportate modifiche a questo problema. Ci sono molti frammenti di codice in giro per semplificare l'applicazione di un carattere tipografico alla tua interfaccia utente in Java, ma non c'è modo di farlo da XML.
CommonsWare

1
@Amit: "Ma questo significa che dovrò creare i miei file .ttf o .otf per i caratteri personalizzati?" - ehm, no. Puoi utilizzare i caratteri TTF / OTF esistenti, anche se potrebbero non funzionare tutti. Il problema su questa domanda è come applicare quei caratteri su un'intera app, che ancora non è possibile, ed è quello a cui mi riferivo nel mio commento.
CommonsWare

1
Questa risposta accettata è obsoleta e sarebbe fantastico aggiornarla o eliminarla.
Sky Kelsey

109

Sì, è possibile.

Devi creare una visualizzazione personalizzata che estenda la visualizzazione del testo.

In attrs.xmlin valuescartella:

<resources>
    <declare-styleable name="MyTextView">
        <attr name="first_name" format="string"/>
        <attr name="last_name" format="string"/>
        <attr name="ttf_name" format="string"/>
    </declare-styleable>
</resources>

In main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:lht="http://schemas.android.com/apk/res/com.lht"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView  android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello"/>
    <com.lht.ui.MyTextView  
        android:id="@+id/MyTextView"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="Hello friends"
        lht:ttf_name="ITCBLKAD.TTF"
        />   
</LinearLayout>

In MyTextView.java:

package com.lht.ui;

import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class MyTextView extends TextView {

    Context context;
    String ttfName;

    String TAG = getClass().getName();

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;

        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            Log.i(TAG, attrs.getAttributeName(i));
            /*
             * Read value of custom attributes
             */

            this.ttfName = attrs.getAttributeValue(
                    "http://schemas.android.com/apk/res/com.lht", "ttf_name");
            Log.i(TAG, "firstText " + firstText);
            // Log.i(TAG, "lastText "+ lastText);

            init();
        }

    }

    private void init() {
        Typeface font = Typeface.createFromAsset(context.getAssets(), ttfName);
        setTypeface(font);
    }

    @Override
    public void setTypeface(Typeface tf) {

        // TODO Auto-generated method stub
        super.setTypeface(tf);
    }

}

4
Funzionerà, ma solo per TextView. Richiederà sottoclassi personalizzate per ogni classe widget che eredita da TextViewdove si desidera la stessa capacità.
CommonsWare

Ciao Manish, grazie per la soluzione. Anche se sto affrontando un problema nell'utilizzo di questo. Continuo a ricevere "nessun identificatore di risorsa trovato per l'attributo ttf_name nel pacchetto com.lht.android"
Kshitij Aggarwal

17
Funzionerà, ma pre-ICS allocherà memoria per i caratteri per ogni visualizzazione che istanzerai: code.google.com/p/android/issues/detail?id=9904 Un modo per risolvere questo problema è creare un file accessibile a livello globale hashmap statica di tutti i caratteri istanziati: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt

Perché abbiamo bisogno di un ciclo ?, Non dovrebbe funzionare con una singola chiamata?
Guillermo Tobar

1
@AlaksiejN. nel caso in cui sia necessario impostare caratteri tipografici diversi per TextView differenti ...
Nick

49

L'ho fatto in un modo più "brute force" che non richiede modifiche al layout xml o alle attività.

Testato su Android dalla versione 2.1 alla 4.4. Eseguilo all'avvio dell'app, nella tua classe Application:

private void setDefaultFont() {

    try {
        final Typeface bold = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_FONT_FILENAME);
        final Typeface italic = Typeface.createFromAsset(getAssets(), DEFAULT_ITALIC_FONT_FILENAME);
        final Typeface boldItalic = Typeface.createFromAsset(getAssets(), DEFAULT_BOLD_ITALIC_FONT_FILENAME);
        final Typeface regular = Typeface.createFromAsset(getAssets(),DEFAULT_NORMAL_FONT_FILENAME);

        Field DEFAULT = Typeface.class.getDeclaredField("DEFAULT");
        DEFAULT.setAccessible(true);
        DEFAULT.set(null, regular);

        Field DEFAULT_BOLD = Typeface.class.getDeclaredField("DEFAULT_BOLD");
        DEFAULT_BOLD.setAccessible(true);
        DEFAULT_BOLD.set(null, bold);

        Field sDefaults = Typeface.class.getDeclaredField("sDefaults");
        sDefaults.setAccessible(true);
        sDefaults.set(null, new Typeface[]{
                regular, bold, italic, boldItalic
        });

    } catch (NoSuchFieldException e) {
        logFontError(e);
    } catch (IllegalAccessException e) {
        logFontError(e);
    } catch (Throwable e) {
        //cannot crash app if there is a failure with overriding the default font!
        logFontError(e);
    }
}

Per un esempio più completo, vedere http://github.com/perchrh/FontOverrideExample


Questa è la soluzione migliore per me.
Igor K

2
l'impostazione predefinita non funziona per me. se uso monospazio e poi imposto code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> monospazio </item> </style> codefunziona ma non per grassetto. ho aggiunto questo codice in una classe che estende Application. è quello il posto corretto? @ P-chan
Christopher Rivera

2
@ChristopherRivera Sì, aggiungilo alla classe Application della tua app, assicurati che funzioni su onCreate. Dando uno sguardo a grepcode.com/file/repository.grepcode.com/java/ext/…, ti suggerirei di sovrascrivere il campo aggiuntivo per monospazio così come quello nel mio codice di esempio sopra!
Per Christian Henden

2
Ok, ho cambiato per il campo SERIF e ha funzionato :)
Abdullah Umer

3
Questa risposta fa riferimento a questa risposta e fornisce un approccio più pulito imho.
adamdport

36

Sebbene io stia votando la risposta di Manish come il metodo più veloce e mirato, ho anche visto soluzioni ingenue che iterano ricorsivamente attraverso una gerarchia di visualizzazione e aggiornano a turno i caratteri tipografici di tutti gli elementi. Qualcosa come questo:

public static void applyFonts(final View v, Typeface fontToSet)
{
    try {
        if (v instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                View child = vg.getChildAt(i);
                applyFonts(child, fontToSet);
            }
        } else if (v instanceof TextView) {
            ((TextView)v).setTypeface(fontToSet);
        }
    } catch (Exception e) {
        e.printStackTrace();
        // ignore
    }
}

Dovresti chiamare questa funzione nelle tue viste sia dopo aver gonfiato il layout che nei onContentChanged()metodi della tua attività .


Abbastanza. A quel tempo, era l'unico modo per farlo entro i tempi del progetto. Una comoda scorciatoia se necessario (:
pospi

23

Sono riuscito a farlo in modo centralizzato, ecco il risultato:

inserisci qui la descrizione dell'immagine

Ho seguito Activityed estendo da esso se ho bisogno di caratteri personalizzati:

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater.Factory;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    getLayoutInflater().setFactory(new Factory() {

        @Override
        public View onCreateView(String name, Context context,
                AttributeSet attrs) {
            View v = tryInflate(name, context, attrs);
            if (v instanceof TextView) {
                setTypeFace((TextView) v);
            }
            return v;
        }
    });
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs); 
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

Ma se sto usando un'attività dal pacchetto di supporto, ad esempio, FragmentActivityallora uso questo Activity:

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class CustomFontFragmentActivity extends FragmentActivity {

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

// we can't setLayout Factory as its already set by FragmentActivity so we
// use this approach
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    View v = super.onCreateView(name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public View onCreateView(View parent, String name, Context context,
        AttributeSet attrs) {
    View v = super.onCreateView(parent, name, context, attrs);
    if (v == null) {
        v = tryInflate(name, context, attrs);
        if (v instanceof TextView) {
            setTypeFace((TextView) v);
        }
    }
    return v;
}

private View tryInflate(String name, Context context, AttributeSet attrs) {
    LayoutInflater li = LayoutInflater.from(context);
    View v = null;
    try {
        v = li.createView(name, null, attrs);
    } catch (Exception e) {
        try {
            v = li.createView("android.widget." + name, null, attrs);
        } catch (Exception e1) {
        }
    }
    return v;
}

private void setTypeFace(TextView tv) {
    tv.setTypeface(FontUtils.getFonts(this, "MTCORSVA.TTF"));
}
}

Non ho ancora testato questo codice con Fragments, ma spero che funzioni.

Il mio FontUtilsè semplice e risolve anche il problema pre-ICS menzionato qui https://code.google.com/p/android/issues/detail?id=9904 :

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Typeface;

public class FontUtils {

private static Map<String, Typeface> TYPEFACE = new HashMap<String, Typeface>();

public static Typeface getFonts(Context context, String name) { 
    Typeface typeface = TYPEFACE.get(name);
    if (typeface == null) {
        typeface = Typeface.createFromAsset(context.getAssets(), "fonts/"
                + name);
        TYPEFACE.put(name, typeface);
    }
    return typeface;
}
}

2
Questo dovrebbe ottenere più voti. Funziona e ha uno screenshot per dimostrazione
ericn

10

Ehi, ho anche bisogno di 2 caratteri diversi nella mia app per diversi widget! Uso in questo modo:

Nella mia classe Application creo un metodo statico:

public static Typeface getTypeface(Context context, String typeface) {
    if (mFont == null) {
        mFont = Typeface.createFromAsset(context.getAssets(), typeface);
    }
    return mFont;
}

Il carattere tipografico String rappresenta xyz.ttf nella cartella degli asset. (ho creato una classe Constants) Ora puoi usarla ovunque nella tua app:

mTextView = (TextView) findViewById(R.id.text_view);
mTextView.setTypeface(MyApplication.getTypeface(this, Constants.TYPEFACE_XY));

L'unico problema è che ne hai bisogno per ogni widget in cui vuoi usare il Font! Ma penso che questo sia il modo migliore.


4

Usando il suggerimento di pospi e lavorando con la proprietà 'tag' come ha fatto Richard , ho creato una classe personalizzata che carica i miei caratteri personalizzati e li applica alle viste in base ai loro tag.

Quindi, in pratica, invece di impostare TypeFace nell'attributo android: fontFamily, stai usando android: tag attritube e impostalo su una delle enumerazioni definite.

public class Fonts {
    private AssetManager mngr;

    public Fonts(Context context) {
        mngr = context.getAssets();
    }
    private enum AssetTypefaces {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    private Typeface getTypeface(AssetTypefaces font) {
        Typeface tf = null;
        switch (font) {
            case RobotoLight:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Light.ttf");
                break;
            case RobotoThin:
                tf = Typeface.createFromAsset(mngr,"fonts/Roboto-Thin.ttf");
                break;
            case RobotoCondensedBold:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Bold.ttf");
                break;
            case RobotoCondensedLight:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Light.ttf");
                break;
            case RobotoCondensedRegular:
                tf = Typeface.createFromAsset(mngr,"fonts/RobotoCondensed-Regular.ttf");
                break;
            default:
                tf = Typeface.DEFAULT;
                break;
        }
        return tf;
    }
    public void setupLayoutTypefaces(View v) {
        try {
            if (v instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++) {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            } else if (v instanceof TextView) {
                if (v.getTag().toString().equals(AssetTypefaces.RobotoLight.toString())){
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedRegular.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedRegular));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedBold.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedBold));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoCondensedLight.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoCondensedLight));
                }else if (v.getTag().toString().equals(AssetTypefaces.RobotoThin.toString())) {
                    ((TextView)v).setTypeface(getTypeface(AssetTypefaces.RobotoThin));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            // ignore
        }
    }
}

Nella tua attività o frammento chiami

Fonts fonts = new Fonts(getActivity());
fonts.setupLayoutTypefaces(mainLayout);

4

Ho trovato una bella soluzione sul blog di Lisa Wray . Con il nuovo data binding è possibile impostare il carattere nei file XML.

@BindingAdapter({"bind:font"})
public static void setFont(TextView textView, String fontName){
    textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}

In XML:

<TextView
app:font="@{`Source-Sans-Pro-Regular.ttf`}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

Potete suggerire un esempio utilizzando il Data Binding? Sarebbe molto apprezzato.
Sri Krishna

3

Penso che ci possa essere un modo più pratico per farlo. La classe seguente imposterà un tipo di carattere personalizzato per tutti i componenti della tua applicazione (con un'impostazione per classe).

/**
 * Base Activity of our app hierarchy.
 * @author SNI
 */
public class BaseActivity extends Activity {

    private static final String FONT_LOG_CAT_TAG = "FONT";
    private static final boolean ENABLE_FONT_LOGGING = false;

    private Typeface helloTypeface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        helloTypeface = Typeface.createFromAsset(getAssets(), "fonts/<your type face in assets/fonts folder>.ttf");
    }

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        View view = super.onCreateView(parent, name, context, attrs);
        return setCustomTypeFaceIfNeeded(name, attrs, view);
    }

    protected View setCustomTypeFaceIfNeeded(String name, AttributeSet attrs, View view) {
        View result = null;
        if ("TextView".equals(name)) {
            result = new TextView(this, attrs);
            ((TextView) result).setTypeface(helloTypeface);
        }

        if ("EditText".equals(name)) {
            result = new EditText(this, attrs);
            ((EditText) result).setTypeface(helloTypeface);
        }

        if ("Button".equals(name)) {
            result = new Button(this, attrs);
            ((Button) result).setTypeface(helloTypeface);
        }

        if (result == null) {
            return view;
        } else {
            if (ENABLE_FONT_LOGGING) {
                Log.v(FONT_LOG_CAT_TAG, "A type face was set on " + result.getId());
            }
            return result;
        }
    }

}

2

Le implementazioni predefinite di LayoutInflater non supportano la specifica del carattere tipografico del carattere da xml. Tuttavia, l'ho visto fare in xml fornendo una fabbrica personalizzata per LayoutInflater che analizzerà tali attributi dal tag xml.

La struttura di base vorrebbe questo.

public class TypefaceInflaterFactory implements LayoutInflater.Factory {

    @Override
    public View onCreateView(String name, Context context, AttributeSet attrs) {
        // CUSTOM CODE TO CREATE VIEW WITH TYPEFACE HERE
        // RETURNING NULL HERE WILL TELL THE INFLATER TO USE THE
        // DEFAULT MECHANISMS FOR INFLATING THE VIEW FROM THE XML
    }

}

public class BaseActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater.from(this).setFactory(new TypefaceInflaterFactory());
    }
}

Questo articolo fornisce una spiegazione più approfondita di questi meccanismi e di come l'autore tenta di fornire il supporto del layout xml per i caratteri tipografici in questo modo. Il codice per l'implementazione dell'autore può essere trovato qui .


1

Impostazione di un carattere personalizzato su un normale ProgressDialog / AlertDialog:

font=Typeface.createFromAsset(getAssets(),"DroidSans.ttf");

ProgressDialog dialog = ProgressDialog.show(this, "titleText", "messageText", true);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("message", "id", "android"))).setTypeface(font);
((TextView)dialog.findViewById(Resources.getSystem().getIdentifier("alertTitle", "id", "android"))).setTypeface(font);

1

Sì, è possibile sovrascrivendo il carattere tipografico predefinito. Ho seguito questa soluzione e ha funzionato come un fascino per tutti i TextViews e anche il testo ActionBar con una singola modifica.

public class MyApp extends Application {

  @Override
  public void onCreate() {
    TypefaceUtil.overrideFont(getApplicationContext(), "SERIF", "fonts/Roboto-Regular.ttf"); // font from assets: "assets/fonts/Roboto-Regular.ttf
  }
}

styles.xml

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/pantone</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
    <item name="android:windowDisablePreview">true</item>
    <item name="android:typeface">serif</item>
</style>

Invece di themes.xml come menzionato nel collegamento sopra, ho menzionato il carattere predefinito da sovrascrivere nel mio styles.xml nel tag del tema dell'app predefinito. I caratteri tipografici predefiniti che possono essere sovrascritti sono serif, sans, monospace e normal.

TypefaceUtil.java

public class TypefaceUtil {

    /**
     * Using reflection to override default typeface
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
     * @param context to work with assets
     * @param defaultFontNameToOverride for example "monospace"
     * @param customFontFileNameInAssets file name of the font from assets
     */
    public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
        try {
            final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);

            final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
            defaultFontTypefaceField.setAccessible(true);
            defaultFontTypefaceField.set(null, customFontTypeface);
        } catch (Exception e) {
            Log.e("Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
        }
    }
}

Inizialmente, non sapevo che i caratteri da sovrascrivere fossero fissi e impostati su valori definiti, ma alla fine mi ha aiutato a capire come Android gestisce i caratteri e i caratteri tipografici ei loro valori predefiniti, il che è un punto di vista diverso.


0

Non so se cambia l'intera app, ma sono riuscito a cambiare alcuni componenti che altrimenti non potrebbero essere modificati in questo modo:

Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lucida Sans Unicode.ttf");
Typeface.class.getField("DEFAULT").setAccessible(true);
Typeface.class.getField("DEFAULT_BOLD").setAccessible(true);
Typeface.class.getField("DEFAULT").set(null, tf);
Typeface.class.getField("DEFAULT_BOLD").set(null, tf);

2
Sfortunatamente questo non funziona più: java.lang.IllegalAccessException: il campo è contrassegnato come "finale" in java.lang.reflect.Field.setField (metodo nativo) in java.lang.reflect.Field.set (Field.java: 556)
CdA

0

Mi piace il suggerimento di pospi. Perché non usare completamente la proprietà 'tag' di una vista (che puoi specificare in XML - 'android: tag') per specificare qualsiasi stile aggiuntivo che non puoi fare in XML. Mi piace JSON, quindi utilizzerei una stringa JSON per specificare un set di chiavi / valori. Questa classe fa il lavoro: chiama semplicemente la Style.setContentView(this, [resource id])tua attività.

public class Style {

  /**
   * Style a single view.
   */
  public static void apply(View v) {
    if (v.getTag() != null) {
      try {
        JSONObject json = new JSONObject((String)v.getTag());
        if (json.has("typeface") && v instanceof TextView) {
          ((TextView)v).setTypeface(Typeface.createFromAsset(v.getContext().getAssets(),
                                                             json.getString("typeface")));
        }
      }
      catch (JSONException e) {
        // Some views have a tag without it being explicitly set!
      }
    }
  }

  /**
   * Style the passed view hierarchy.
   */
  public static View applyTree(View v) {
    apply(v);
    if (v instanceof ViewGroup) {
      ViewGroup g = (ViewGroup)v;
      for (int i = 0; i < g.getChildCount(); i++) {
        applyTree(g.getChildAt(i));
      }
    }
    return v;
  }

  /**
   * Inflate, style, and set the content view for the passed activity.
   */
  public static void setContentView(Activity activity, int resource) {
    activity.setContentView(applyTree(activity.getLayoutInflater().inflate(resource, null)));
  }
}

Ovviamente vorresti gestire più del semplice carattere tipografico per rendere utile l'utilizzo di JSON.

Un vantaggio della proprietà 'tag' è che puoi impostarlo su uno stile di base che usi come tema e quindi farlo applicare automaticamente a tutte le tue viste. EDIT: in questo modo si verifica un arresto anomalo durante l'inflazione su Android 4.0.3. È comunque possibile utilizzare uno stile e applicarlo individualmente alle visualizzazioni di testo.

Una cosa che vedrai nel codice - alcune visualizzazioni hanno un tag senza che ne sia impostato esplicitamente uno - stranamente è la stringa "Αποκοπή" - che è "tagliato" in greco, secondo google translate! Che diavolo...?


0

La risposta di @ majinboo è stata rivista per le prestazioni e la gestione della memoria. Qualsiasi attività correlata a più di un font può utilizzare questa classe Font fornendo il costruttore stesso come parametro.

@Override
public void onCreate(Bundle savedInstanceState)
{
    Font font = new Font(this);
}

La classe dei caratteri modificati è la seguente:

public class Fonts
{
    private HashMap<AssetTypefaces, Typeface> hashMapFonts;

    private enum AssetTypefaces
    {
        RobotoLight,
        RobotoThin,
        RobotoCondensedBold,
        RobotoCondensedLight,
        RobotoCondensedRegular
    }

    public Fonts(Context context)
    {
        AssetManager mngr = context.getAssets();

        hashMapFonts = new HashMap<AssetTypefaces, Typeface>();
        hashMapFonts.put(AssetTypefaces.RobotoLight, Typeface.createFromAsset(mngr, "fonts/Roboto-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoThin, Typeface.createFromAsset(mngr, "fonts/Roboto-Thin.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedBold, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Bold.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedLight, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Light.ttf"));
        hashMapFonts.put(AssetTypefaces.RobotoCondensedRegular, Typeface.createFromAsset(mngr, "fonts/RobotoCondensed-Regular.ttf"));
    }

    private Typeface getTypeface(String fontName)
    {
        try
        {
            AssetTypefaces typeface = AssetTypefaces.valueOf(fontName);
            return hashMapFonts.get(typeface);
        }
        catch (IllegalArgumentException e)
        {
            // e.printStackTrace();
            return Typeface.DEFAULT;
        }
    }

    public void setupLayoutTypefaces(View v)
    {
        try
        {
            if (v instanceof ViewGroup)
            {
                ViewGroup vg = (ViewGroup) v;
                for (int i = 0; i < vg.getChildCount(); i++)
                {
                    View child = vg.getChildAt(i);
                    setupLayoutTypefaces(child);
                }
            }
            else if (v instanceof TextView)
            {
                ((TextView) v).setTypeface(getTypeface(v.getTag().toString()));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            // ignore
        }
    }
}

0

Lavorare per Xamarin.Android:

Classe:

public class FontsOverride
{
    public static void SetDefaultFont(Context context, string staticTypefaceFieldName, string fontAssetName)
    {
        Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName);
        ReplaceFont(staticTypefaceFieldName, regular);
    }

    protected static void ReplaceFont(string staticTypefaceFieldName, Typeface newTypeface)
    {
        try
        {
            Field staticField = ((Java.Lang.Object)(newTypeface)).Class.GetDeclaredField(staticTypefaceFieldName);
            staticField.Accessible = true;
            staticField.Set(null, newTypeface);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

Implementazione dell'applicazione:

namespace SomeAndroidApplication
{
    [Application]
    public class App : Application
    {
        public App()
        {

        }

        public App(IntPtr handle, JniHandleOwnership transfer)
            : base(handle, transfer)
        {

        }

        public override void OnCreate()
        {
            base.OnCreate();

            FontsOverride.SetDefaultFont(this, "MONOSPACE", "fonts/Roboto-Light.ttf");
        }
    }
}

Stile:

<style name="Theme.Storehouse" parent="Theme.Sherlock">
    <item name="android:typeface">monospace</item>
</style>

0

Sembra che l'utilizzo di caratteri personalizzati sia stato semplificato con Android O, in pratica puoi utilizzare xml per ottenere ciò. Ho allegato un collegamento alla documentazione ufficiale di Android come riferimento e spero che questo possa aiutare le persone che hanno ancora bisogno di questa soluzione. Lavorare con caratteri personalizzati in Android


0

Può essere utile sapere che a partire da Android 8.0 (livello API 26) è possibile utilizzare un font personalizzato in XML .

In poche parole, puoi farlo nel modo seguente.

  1. Metti il ​​carattere nella cartella res/font.

  2. O usalo nell'attributo di un widget

<Button android:fontFamily="@font/myfont"/>

o inseriscilo res/values/styles.xml

<style name="MyButton" parent="android:Widget.Button">
    <item name="android:fontFamily">@font/myfont</item>
</style>

e usalo come stile

<Button style="@style/MyButton"/>

0

Usa l'attributo "fontPath" direttamente nel file xml.

da utilizzare in style.xml

<item name = "fontPath"> font / ProximaNovaSemibold.ttf </item>

per l'uso nel file di layout diretto

FontPath = "font / ProximaNovaBold.ttf"

(Nota: non è necessario utilizzare l'attributo app / Android nel prefisso)


-6

Assolutamente possibile. Molti modi per farlo. Il modo più veloce, crea la condizione con il metodo try - catch .. prova la tua determinata condizione di stile di carattere, individua l'errore e definisci l'altro stile di carattere.


7
potete fornire una demo per dimostrare che rispondete?
Mark
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.