Использование пользовательского шрифта в Android - PullRequest
110 голосов
/ 04 июня 2010

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

Итак,

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

Ответы [ 19 ]

1 голос
/ 18 июля 2017

Да, это возможно путем переопределения гарнитуры по умолчанию. Я следовал этому решению, и оно работало как очарование для всех 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>

Вместо themes.xml, как упомянуто в приведенной выше ссылке, я упомянул шрифт по умолчанию для переопределения в моем файле styles.xml в теге темы приложения по умолчанию. Шрифтами по умолчанию, которые могут быть перезаписаны, являются serif, sans, monospace и 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);
        }
    }
}

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

1 голос
/ 26 января 2012

Установка обычного шрифта для обычного 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 голосов
/ 09 февраля 2019

Может быть полезно знать, что начиная с Android 8.0 (уровень API 26) вы можете использовать собственный шрифт в XML .

Проще говоря, вы можете сделать это следующим образом.

  1. Поместите шрифт в папку res/font.

  2. Либо используйте его в атрибуте виджета

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

или положить в res/values/styles.xml

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

и используйте его как стиль

<Button style="@style/MyButton"/>
0 голосов
/ 28 июня 2017

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

0 голосов
/ 10 марта 2015

Работает на 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 голосов
/ 19 октября 2014

@ ответ majinboo пересмотрен для управления производительностью и памятью. Любой более чем один шрифт, связанный с Activity, может использовать этот класс 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 голосов
/ 20 июня 2012

Мне нравится предложение поспи.Почему бы не сделать все возможное, используйте свойство 'tag' представления (которое вы можете указать в 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' заключается в том, что вы можете установить его в базовом стиле, который вы используете в качестве темы, и, таким образом, применять его ко всем вашим представлениям автоматически. РЕДАКТИРОВАТЬ: Это приводит к падению во время инфляции на Android 4.0.3.Вы по-прежнему можете использовать стиль и применять его к текстовым представлениям по отдельности.

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

0 голосов
/ 12 октября 2012

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

0 голосов
/ 17 февраля 2011

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

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