Использование пользовательского шрифта в Android

105

Я хочу использовать пользовательский шрифт для моего приложения Android, которое я создаю.
Я могу индивидуально изменить шрифт каждого объекта из кода, но у меня их сотни.

Итак,

  • Есть ли способ сделать это из XML? [Настройка пользовательского шрифта]
  • Есть ли способ сделать это из кода в одном месте, чтобы сказать, что все приложение и все компоненты должны использовать пользовательский шрифт вместо стандартного?
  • 0
    stackoverflow.com/questions/5541058/… Посмотрите на этот пост, я разместил полный код здесь относительно этой проблемы
  • 0
    Вы можете использовать статические переменные в своей основной деятельности для хранения ссылок на встроенные шрифты. Это может привести к тому, что будет один постоянный набор шрифтов, который не будет выбран GC.
Показать ещё 2 комментария
Теги:
fonts
layout

19 ответов

77
Лучший ответ

Есть ли способ сделать это из XML?

Нет, извините. Вы можете указывать только встроенные шрифты через XML.

Есть ли способ сделать это из кода в одно место, чтобы сказать, что весь приложение и все компоненты вместо этого следует использовать настраиваемый шрифт по умолчанию?

Не то, чтобы я знал.

  • 0
    Ой! Это действительно разочаровывает. Я искал весь интернет и был настроен оптимистично. Означает ли это, что я должен из кода установить гарнитуру для каждого компонента пользовательского интерфейса?
  • 4
    @Codevalley: Ну, во многих отношениях лучший ответ не суетиться с пользовательскими шрифтами. Они имеют тенденцию быть большими, увеличивая ваши загрузки и уменьшая количество людей, которые будут загружать и продолжать использовать ваше приложение.
Показать ещё 17 комментариев
104

Да Возможно.

Вам нужно создать настраиваемое представление, расширяющее текстовое представление.

В attrs.xml в папке values:

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

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

В 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
    Это будет работать, но только для TextView . Это потребует пользовательских подклассов для каждого класса виджетов, который наследуется от TextView где требуется такая же возможность.
  • 0
    Мне нужно больше помощи относительно этого решения, кто-нибудь может предоставить, пожалуйста. ???
Показать ещё 10 комментариев
47

Я сделал это более "грубой силой", которая не требует изменений в макете xml или Activities.

Протестировано на Android версии 2.1 - 4.4. Запустите это при запуске приложения, в своем классе 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);
    }
}

Для более полного примера см. http://github.com/perchrh/FontOverrideExample

  • 0
    Блестящий, работает как шарм на 4.1.2
  • 0
    Это лучшее решение для меня.
Показать ещё 10 комментариев
35

Хотя я поддерживаю Маниш-ответ как самый быстрый и наиболее целенаправленный метод, я также видел наивные решения, которые рекурсивно повторяют иерархию представлений и обновляют шрифты всех элементов по очереди. Что-то вроде этого:

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

Вам нужно будет вызвать эту функцию в своих представлениях как после раздувания макета, так и в методах Activity onContentChanged().

  • 13
    Святое время выполнения спектакля поразило Бэтмена.
  • 0
    Довольно много. В то время это был единственный способ сделать это в сроки проекта. Удобный ярлык при необходимости (:
23

Я смог сделать это централизованно, вот результат:

Изображение 4543

У меня есть следующий Activity, и я от него расширяюсь, если мне нужны пользовательские шрифты:

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

Но если я использую активность из пакета поддержки, например. FragmentActivity, то я использую этот 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"));
}
}

Я еще не тестировал этот код с Fragment, но, надеюсь, он будет работать.

Мой FontUtils прост, который также решает проблему, предшествующую ICS, упомянутую здесь 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
    Это должно получить больше голосов. Это работает, и у него есть скриншот для демонстрации
  • 0
    Это прекрасно работает для деятельности, но не для фрагментов
10

Эй, мне также нужны 2 разных шрифта в моем приложении для разных альбомов! Я использую этот способ:

В моем классе приложения я создаю статический метод:

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

Строковый шрифт представляет xyz.ttf в папке с активами. (я создал класс констант) Теперь вы можете использовать это везде в своем приложении:

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

Единственная проблема: вам нужно это для каждого виджета, где вы хотите использовать Шрифт! Но я думаю, что это лучший способ.

4

Используя предложение pospi и работая с свойством tag, например Richard, я создал собственный класс, который загружает мои пользовательские шрифты и применяет их к представлениям в соответствии с их теги.

Итак, вместо установки TypeFace в атрибуте android: fontFamily вы используете android: tag attritube и установите его в одно из определенных перечислений.

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

В вашей деятельности или фрагменте вы просто вызываете

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

Я нашел хорошее решение на блоге Lisa Wray. С новой привязкой данных можно установить шрифт в ваших XML файлах.

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

В XML:

<TextView
app:font="@{`Source-Sans-Pro-Regular.ttf`}"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
  • 0
    Можете ли вы предложить пример использования привязки данных? Это будет высоко ценится.
3

Я думаю, что может быть более удобный способ сделать это. Следующий класс установит лицо специального типа для всех ваших компонентов вашего приложения (с настройкой для каждого класса).

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

Стандартные реализации LayoutInflater не поддерживают указание шрифта шрифта из xml. Я, однако, видел это в xml, предоставляя собственный factory для LayoutInflater, который будет анализировать такие атрибуты из тега xml.

Базовая структура хотела бы этого.

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

В этой статье содержится более подробное объяснение этих механизмов и то, как автор пытается обеспечить поддержку макета xml для шрифтов таким образом. Код для реализации автора можно найти здесь.

1

Да, это возможно, переопределив шрифт по умолчанию. Я последовал за этим решением, и он работал как прелесть для всех текстов TextViews и ActionBar тоже с одним изменением.

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>

Вместо topic.xml, как упоминалось в приведенной выше ссылке, я упомянул шрифт по умолчанию для переопределения в моем styles.xml в теге темы приложения по умолчанию. По умолчанию шрифты, которые могут быть перезаписаны, являются засечками, без изменений, моноширинными и нормальными.

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

Вначале я не знал, что шрифты, которые будут перезаписаны, являются фиксированными и заданы с помощью определенных значений, но в конечном итоге это помогло мне понять, как Android имеет дело с шрифтами и шрифтами и их значениями по умолчанию, что является другим моментом.

1

Настройка настраиваемого шрифта для обычного режима 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);
0

Новая библиотека поддержки 26 теперь позволяет использовать шрифты в XML.

Вот как это сделать Шрифты в XML

0

Похоже, что использование пользовательских шрифтов стало проще с Android O, вы можете в основном использовать xml для достижения этого. Я приложил ссылку на официальную документацию Android для справки, и, надеюсь, это поможет людям, которые все еще нуждаются в этом решении. Работа с пользовательскими шрифтами в Android

0

Работа для Xamarin.Android:

Класс:

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

Внедрение приложений:

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

Стиль:

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

@majinboo ответ пересмотрен для управления производительностью и памятью. Любой объект, связанный с одним шрифтом, может использовать этот класс Font, указав сам конструктор как параметр.

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

Класс пересмотренных шрифтов выглядит следующим образом:

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

Мне нравится предложение pospi. Почему бы не обойтись без использования свойства тега view (которое вы можете указать в XML - "android: tag" ), чтобы указать какой-либо дополнительный стиль, который вы не можете сделать в XML. Мне нравится JSON, поэтому я бы использовал строку JSON для указания набора ключей/значений. Этот класс выполняет работу - просто вызовите Style.setContentView(this, [resource id]) в своей деятельности.

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

Очевидно, что вы хотите обрабатывать больше, чем просто шрифт, чтобы использовать JSON.

Преимущество свойства "tag" заключается в том, что вы можете установить его в базовом стиле, который вы используете в качестве темы, и, следовательно, примените его ко всем вашим представлениям автоматически. EDIT:. Это приводит к сбою во время инфляции на Android 4.0.3. Вы все равно можете использовать стиль и применять его к текстовым представлениям индивидуально.

Одна вещь, которую вы увидите в коде - в некоторых представлениях есть тег без того, чтобы он был явно установлен, - это, как правило, строка "Αποκοπή" - которая "вырезана" в греческом языке, согласно google translate! Какого черта...?

0

Я не знаю, изменило ли оно все приложение, но мне удалось изменить некоторые компоненты, которые в противном случае не могли быть изменены:

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
    К сожалению, это больше не работает: java.lang.IllegalAccessException: поле помечено как «окончательное» в java.lang.reflect.Field.setField (собственный метод) в java.lang.reflect.Field.set (Field.java: 556)
-5

Абсолютно возможно. Много способов сделать это. Самый быстрый способ, создать условие с методом try-catch. попробуйте определенное условие стиля шрифта, поймайте ошибку и определите другой стиль шрифта.

  • 7
    Можете ли вы предоставить демо-версию, чтобы доказать свой ответ?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню