Usando uma fonte personalizada no Android


111

Quero usar uma fonte personalizada para meu aplicativo Android que estou criando.
Posso alterar individualmente o tipo de letra de cada objeto do Code, mas tenho centenas deles.

Assim,

  • Existe uma maneira de fazer isso a partir do XML? [Definindo uma fonte personalizada]
  • Existe uma maneira de fazer isso a partir do código em um lugar, para dizer que todo o aplicativo e todos os componentes devem usar o tipo de letra personalizado em vez do padrão?

stackoverflow.com/questions/5541058/… Olhe para este post, eu postei o código completo aqui a respeito desse problema
Manish Singla,

Você pode usar variáveis ​​estáticas em sua atividade principal para manter referências às fontes incorporadas. Isso faria com que houvesse um conjunto persistente de fontes que não será selecionado pelo GC.
Jacksonkr

Método de fábrica. Ou um método que obtém sua visão e define todas as configurações de fonte e tipo de letra.
mtmurdock,

A nova biblioteca de suporte 26 agora permite que você use fontes em XML. Veja como fazer fontes em XML
Vinicius Silva

Respostas:


80

Existe uma maneira de fazer isso a partir do XML?

Não, desculpe. Você só pode especificar as fontes internas por meio de XML.

Existe uma maneira de fazer isso a partir do código em um lugar, para dizer que todo o aplicativo e todos os componentes devem usar o tipo de letra personalizado em vez do padrão?

Não que eu saiba.

Há uma variedade de opções para eles hoje em dia:

  • Recursos de fonte e backports no Android SDK, se você estiver usando appcompat

  • Bibliotecas de terceiros para quem não usa appcompat, embora nem todas suportem a definição da fonte nos recursos de layout


4
@Codevalley: Bem, em muitos aspectos, a melhor resposta é não se preocupar com fontes personalizadas. Eles tendem a ser grandes, tornando seus downloads maiores e reduzindo o número de pessoas que farão o download e continuarão usando seu aplicativo.
CommonsWare

22
@CommonsWare: Não concordo necessariamente. O tipo de letra é parte integrante do estilo de interface do usuário, como você faz com imagens de plano de fundo, etc. E o tamanho nem sempre é necessariamente grande. Por exemplo, a fonte no meu caso é de apenas 19,6 KB :)
Codevalley

2
@Amit: Não houve nenhuma mudança neste problema. Existem muitos trechos de código para ajudar a simplificar a aplicação de um tipo de letra à sua IU em Java, mas não há como fazer isso a partir de XML.
CommonsWare

1
@Amit: "Mas isso significa que terei que criar meus próprios arquivos .ttf ou .otf para fontes personalizadas?" - hum, não. Você pode usar fontes TTF / OTF existentes, embora nem todas funcionem. O problema desta questão é como aplicar essas fontes em um aplicativo inteiro, o que ainda não é possível, e é a isso que me referi em meu comentário.
CommonsWare

1
Essa resposta aceita está obsoleta e seria ótimo atualizá-la ou excluí-la.
Sky Kelsey

109

Sim, é possível.

Você deve criar uma visualização personalizada que amplie a visualização do texto.

Em attrs.xmlna valuespasta:

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

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

Em 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
Isso vai funcionar, mas apenas para TextView. Exigirá subclasses personalizadas para cada classe de widget que herda de TextViewonde o mesmo recurso é desejado.
CommonsWare

Oi Manish, Obrigado pela solução. Embora eu esteja enfrentando um problema em usar isso. Continuo recebendo 'nenhum identificador de recurso encontrado para o atributo ttf_name no pacote com.lht.android'
Kshitij Aggarwal

17
Isso funcionará, mas o pré-ICS alocará memória para as fontes para cada visualização que você instanciar: code.google.com/p/android/issues/detail?id=9904 Uma maneira de corrigir isso é criar um acesso globalmente hashmap estático de todas as fontes instanciadas: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt

Por que precisamos de um loop ?, Não deveria funcionar com uma única chamada?
Guillermo Tobar

1
@AlaksiejN. caso você precise definir fontes diferentes para TextViews diferentes ...
Nick

49

Eu fiz isso de uma forma mais "força bruta" que não requer alterações no xml de layout ou nas Atividades.

Testado no Android versão 2.1 a 4.4. Execute isso na inicialização do aplicativo, em sua classe de aplicativo:

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

Para um exemplo mais completo, veja http://github.com/perchrh/FontOverrideExample


Esta é a melhor solução para mim.
Igor K de

2
padrão não funciona para mim. se eu usar monoespaço e depois definir code<style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> monoespaço </item> </style> code, funcionará, mas não para negrito. Eu adicionei este código em uma classe que estende Application. esse é o lugar correto? @ P-chan
Christopher Rivera

2
@ChristopherRivera Sim, adicione-o à classe Application do seu aplicativo, certifique-se de que ele seja executado em onCreate. Dando uma olhada em grepcode.com/file/repository.grepcode.com/java/ext/… Eu sugiro que você substitua o campo adicional para monoespaço, bem como aquele em meu código de exemplo acima!
Por Christian Henden

2
Ok, mudei para o campo SERIF e funcionou :)
Abdullah Umer

3
Esta resposta faz referência a esta resposta e fornece uma abordagem mais limpa imho.
adamdport

36

Embora eu esteja votando positivamente na resposta de Manish como o método mais rápido e direcionado, também vi soluções ingênuas que apenas iteram recursivamente por meio de uma hierarquia de visualização e atualizam as fontes de todos os elementos por sua vez. Algo assim:

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

Você precisaria chamar esta função em suas visualizações após inflar o layout e nos onContentChanged()métodos de sua Activity .


Bastante. Na época, era a única maneira de fazer isso dentro dos prazos do projeto. Um atalho útil, se necessário (:
pospi de

23

Consegui fazer isso de forma centralizada, aqui está o resultado:

insira a descrição da imagem aqui

Tenho a seguir Activitye estendo a partir dela se precisar de fontes personalizadas:

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

Mas se estou usando uma atividade do pacote de suporte, por exemplo FragmentActivity, eu uso isso 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"));
}
}

Não testei este código com Fragments ainda, mas espero que funcione.

My FontUtilsis simple, que também resolve o problema pré-ICS mencionado aqui 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
Isso deve gerar mais votos. Funciona e tem uma captura de tela para demonstração
ericn

10

Ei, eu também preciso de 2 fontes diferentes no meu aplicativo para widgeds diferentes! Eu uso desta forma:

Na minha classe Application, crio um método estático:

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

O tipo de letra String representa o xyz.ttf na pasta de ativos. (eu criei uma classe Constants) Agora você pode usar isso em qualquer lugar em seu aplicativo:

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

O único problema é que você precisa disso para cada widget em que deseja usar o Font! Mas acho que essa é a melhor maneira.


4

Usando a sugestão de pospi e trabalhando com a propriedade 'tag' como Richard fez, eu criei uma classe personalizada que carrega minhas fontes personalizadas e as aplica às visualizações de acordo com suas tags.

Basicamente, em vez de definir o TypeFace no atributo android: fontFamily, você está usando android: tag attritube e defini-lo como um dos enums definidos.

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

Em sua atividade ou fragmento, você acabou de chamar

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

4

Encontrei uma boa solução no blog da Lisa Wray . Com a nova vinculação de dados, é possível definir a fonte em seus arquivos XML.

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

Em XML:

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

Você pode sugerir um exemplo usando o Data Binding? Isso seria muito apreciado.
Sri Krishna de

3

Acho que pode haver uma maneira mais prática de fazer isso. A classe a seguir definirá uma face de tipo personalizada para todos os componentes do seu aplicativo (com uma configuração por 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

As implementações padrão do LayoutInflater não suportam a especificação do tipo de fonte do xml. No entanto, vi isso ser feito em xml, fornecendo uma fábrica personalizada para o LayoutInflater que analisará esses atributos da tag xml.

A estrutura básica gostaria disso.

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

Este artigo fornece uma explicação mais detalhada desses mecanismos e como o autor tenta fornecer suporte de layout xml para fontes dessa forma. O código para a implementação do autor pode ser encontrado aqui .


1

Definindo uma fonte personalizada para um ProgressDialog / AlertDialog regular:

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

Sim, é possível substituindo o tipo de letra padrão. Segui esta solução e funcionou perfeitamente para todos os textos TextViews e ActionBar com uma única alteração.

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>

Em vez de themes.xml, conforme mencionado no link acima, mencionei a fonte padrão para substituir em meu styles.xml em minha tag de tema de aplicativo padrão. As fontes padrão que podem ser substituídas são serif, sans, monoespaçada 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);
        }
    }
}

Inicialmente, eu não sabia que as fontes a serem sobrescritas eram fixas e um conjunto de valores definidos, mas eventualmente isso me ajudou a entender como o Android lida com fontes e fontes e seus valores padrão, o que é um ponto diferente.


0

Não sei se isso muda todo o aplicativo, mas consegui mudar alguns componentes que não poderiam ser alterados ao fazer isto:

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
Infelizmente, isso não funciona mais: java.lang.IllegalAccessException: o campo está marcado como 'final' em java.lang.reflect.Field.setField (Native Method) em java.lang.reflect.Field.set (Field.java: 556)
BoD

0

Gosto da sugestão do pospi. Por que não usar a propriedade 'tag' de uma visualização (que você pode especificar em XML - 'android: tag') para especificar qualquer estilo adicional que você não pode fazer em XML. Eu gosto de JSON, então usaria uma string JSON para especificar um conjunto de chave / valor. Esta classe faz o trabalho - basta chamar Style.setContentView(this, [resource id])sua atividade.

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

Obviamente, você gostaria de lidar com mais do que apenas o tipo de letra para fazer valer a pena usar JSON.

Um benefício da propriedade 'tag' é que você pode defini-lo em um estilo base que você usa como um tema e, portanto, aplicá-lo a todas as suas visualizações automaticamente. EDIT: Fazer isso resulta em uma falha durante a inflação no Android 4.0.3. Você ainda pode usar um estilo e aplicá-lo às visualizações de texto individualmente.

Uma coisa que você verá no código - algumas visualizações têm uma tag sem uma explicitamente definida - estranhamente é a string 'Αποκοπή' - que é 'cortada' em grego, de acordo com o google tradutor! Que diabos...?


0

A resposta de @ majinboo é revisada para gerenciamento de desempenho e memória. Qualquer atividade relacionada a mais de uma fonte pode usar esta classe Font, fornecendo o próprio construtor como parâmetro.

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

A classe revisada de fontes é a seguinte:

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

Trabalhando para 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);
        }
    }
}

Implementação do aplicativo:

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

Estilo:

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

0

Parece que o uso de fontes personalizadas ficou mais fácil com o Android O, você pode basicamente usar o xml para conseguir isso. Anexei um link para a documentação oficial do Android para referência e espero que isso ajude as pessoas que ainda precisam desta solução. Trabalhar com fontes personalizadas no Android


0

Pode ser útil saber que a partir do Android 8.0 (API de nível 26), você pode usar uma fonte personalizada em XML .

Simplificando, você pode fazer isso da seguinte maneira.

  1. Coloque a fonte na pasta res/font.

  2. Use-o no atributo de um widget

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

ou colocá-lo em res/values/styles.xml

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

e usá-lo como um estilo

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

0

Use o atributo "fontPath" diretamente no arquivo xml.

para uso em style.xml

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

para uso em arquivo de layout direto

fontPath = "fonts / ProximaNovaBold.ttf"

(Observação: não há necessidade de usar o atributo app / android no prefixo)


-6

É absolutamente possível. Muitas maneiras de fazer isso. A maneira mais rápida, crie uma condição com o método try-catch .. tente uma determinada condição de estilo de fonte, identifique o erro e defina o outro estilo de fonte.


7
você pode fornecer uma demonstração para provar sua resposta?
Marcar
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.