Как установить семейство шрифтов по умолчанию для всего приложения Android

283

Я использую светлый шрифт Roboto в своем приложении. Чтобы установить шрифт, я должен добавить android:fontFamily="sans-serif-light"к каждому представлению. Есть ли способ объявить шрифт Roboto как семейство шрифтов по умолчанию для всего приложения? Я пытался так, но это не сработало.

<style name="AppBaseTheme" parent="android:Theme.Light"></style>

<style name="AppTheme" parent="AppBaseTheme">
    <item name="android:fontFamily">sans-serif-light</item>
</style>
tomrozb
источник
2
Это может вам помочь: stackoverflow.com/a/16883281/1329733
Джейкоб Р.
2
Теперь вы можете указывать пользовательские шрифты прямо из XML в Android Studio 3.0 developer.android.com/guide/topics/ui/look-and-feel/…
7

Ответы:

289

Ответ - да.

Глобал Робото лайт для TextViewи Buttonклассов:

<style name="AppTheme" parent="AppBaseTheme">
    <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
    <item name="android:buttonStyle">@style/RobotoButtonStyle</item>
</style>

<style name="RobotoTextViewStyle" parent="android:Widget.TextView">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

<style name="RobotoButtonStyle" parent="android:Widget.Holo.Button">
    <item name="android:fontFamily">sans-serif-light</item>
</style>

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

<application
    android:theme="@style/AppTheme" >
</application>

Он будет работать только со встроенными шрифтами, такими как Roboto, но это был вопрос. Для пользовательских шрифтов (например, загружаемых из ресурсов) этот метод не будет работать.

РЕДАКТИРОВАТЬ 13/13/15

Если вы используете темы AppCompat, не забудьте удалить android:префикс. Например:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
    <item name="buttonStyle">@style/RobotoButtonStyle</item>
</style>

Обратите внимание, что префикс buttonStyleне содержит android:, но textViewStyleдолжен содержать его.

tomrozb
источник
4
Откуда вы взяли sans-serif-lightценность? Есть ли список допустимых значений fontFamilyгде-то? Я просматривал документы, а также файлы тем и стилей в источнике Android и ничего не могу найти.
Кристофер Перри
34
это возможно только для уровня API 16 ... имя "android: fontFamily" существует только на уровне 16 или выше ... есть ли способ сделать это также для API 14, например?
Лоренцо Барбальи
3
@LorenzoBarbagli, вы можете проверить каллиграфию
Брейс Габин
10
Что мне делать, если у меня есть собственный шрифт?
Рохит Тигга
2
да, я также хочу добавить пользовательский шрифт для всего приложения. Как я могу это сделать ?. Нужно ли мне переопределить TextView и заменить все TextView, как предложено в первом ответе
Джон
145

С выпуском Android Oreo вы можете использовать библиотеку поддержки для достижения этой цели.

  1. Проверьте ваше приложение build.gradle, если у вас есть библиотека поддержки > = 26.0.0
  2. Добавьте папку « шрифт » в папку ресурсов и добавьте туда свои шрифты
  3. Ссылка на семейство шрифтов по умолчанию в основном стиле вашего приложения:

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
       <item name="android:fontFamily">@font/your_font</item>
       <item name="fontFamily">@font/your_font</item> <!-- target android sdk versions < 26 and > 14 if theme other than AppCompat -->
    </style>

Проверьте https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html для получения более подробной информации.

Жоао Магальес
источник
9
При нацеливании на API 26+ это должен быть принятый метод. При использовании библиотеки поддержки просто удалите android:префикс
webo80
2
если вы используете только префиксную версию, это нормально.
Приставка с
2
Это не устанавливает шрифт везде ... например, если у вас есть стили, которые происходят от него Base.TextAppearance.AppCompat, он там не используется.
Ixx
3
@ Ixx, как переопределить эти стили?
Primož Kralj
2
Не забывайте также использовать AppCompatTextView при настройке API <26
Codelicious
38

Чтобы изменить шрифт приложения, выполните следующие действия:

  1. Внутри resкаталога создайте новый каталог и назовите его font.
  2. Вставьте ваш шрифт .ttf / .otf в папку шрифтов. Убедитесь, что имя шрифта состоит из строчных букв и подчеркивания.
  3. Внутри res-> values-> styles.xmlвнутри <resources>-> <style>добавить свой шрифт <item name="android:fontFamily">@font/font_name</item>.

введите описание изображения здесь

Теперь весь текст вашего приложения должен быть в том источнике, который вы добавили.

парень
источник
8
при использовании пользовательских шрифтов, как я могу добавить жирный шрифт наряду с обычными шрифтами?
Раджбир Шиен
Это работает только с API уровня 26 и выше, как насчет API 21 и ниже?
Зулькарнайн шах
34

ЧИТАЙТЕ ОБНОВЛЕНИЯ НИЖЕ

У меня была та же проблема с встраиванием нового шрифта, и, наконец, я получил его для работы с расширением TextView и установил внутри шрифт typefont.

public class YourTextView extends TextView {

    public YourTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public YourTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public YourTextView(Context context) {
        super(context);
        init();
    }

    private void init() {
        Typeface tf = Typeface.createFromAsset(context.getAssets(),
            "fonts/helveticaneue.ttf");
        setTypeface(tf);
    }
}

Вы должны изменить элементы TextView позже на с каждого элемента. И если вы используете UI-Creator в Eclipse, иногда он не показывает TextViews правильно. Была единственная вещь, которая работает для меня ...

ОБНОВИТЬ

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

ОБНОВЛЕНИЕ 2

Начиная с API уровня 26 и доступного в «библиотеке поддержки», вы можете использовать

android:fontFamily="@font/embeddedfont"

Дополнительная информация: шрифты в XML

Longi
источник
25
Это не решение. Я использую много разных представлений, не только TextView. Я хочу один раз установить шрифт и забыть об этом. Кроме того, ваш код создает новый объект для каждого TextView. По крайней мере, объявите поле как статическое, чтобы один раз загрузить шрифт из ресурсов.
Томрозб
2
... ну, есть функция поиска и замены, которая в этом случае работает очень хорошо
longi
1
Это не сработает. Вы не можете вызвать, getContext()когда переменная является статической. Вы должны реализовать его как одноэлементный способ, иначе текущий код даже не скомпилируется.
Tomrozb
1
я вернул последний коммит
Лонги
1
@tomrozb: D Я только что понял, что последние быстрые изменения, которые я сделал, были из-за ваших комментариев! так как у вас достаточно очков, вы можете сами оптимизировать пример кода. иначе мы еще поговорим на эту тему через несколько лет, когда никто больше не заботится о смартфонах;)
longi
9

Добавьте эту строку кода в ваш файл res / value / styles.xml

<item name="android:fontFamily">@font/circular_medium</item>

весь стиль будет выглядеть так

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:fontFamily">@font/circular_medium</item>
</style>

замените «циркуляр_медиум» на собственное имя шрифта ..

nirazverma
источник
6

Не говорите о производительности, для пользовательского шрифта вы можете использовать рекурсивный цикл для всех видов и установить гарнитуру, если это TextView:

public class Font {
    public static void setAllTextView(ViewGroup parent) {
        for (int i = parent.getChildCount() - 1; i >= 0; i--) {
            final View child = parent.getChildAt(i);
            if (child instanceof ViewGroup) {
                setAllTextView((ViewGroup) child);
            } else if (child instanceof TextView) {
                ((TextView) child).setTypeface(getFont());
            }
        }
    }

    public static Typeface getFont() {
        return Typeface.createFromAsset(YourApplicationContext.getInstance().getAssets(), "fonts/whateverfont.ttf");
    }
}

Во всей вашей деятельности передайте текущую ViewGroup ей после setContentView, и это будет сделано:

ViewGroup group = (ViewGroup) getWindow().getDecorView().findViewById(android.R.id.content);
Font.setAllTextView(group);

Для фрагмента вы можете сделать что-то подобное.

Аллен Чан
источник
1
Звучит здорово, но интересно, как заставить это работать в содержимом recyclerView?
Сружан Барай,
Я только что попробовал это. слишком тяжелый для рендеринга. Замедление, recyclerViewкак в аду.
Сружан Барай
Абсолютно не рекомендуется для любого представления списка, этот трюк только для экономии времени для статического представления кода.
Аллен Чан
5

Еще один способ сделать это для всего приложения - использовать рефлексию, основанную на этом ответе.

public class TypefaceUtil {
    /**
     * Using reflection to override default typefaces
     * NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE
     * OVERRIDDEN
     *
     * @param typefaces map of fonts to replace
     */
    public static void overrideFonts(Map<String, Typeface> typefaces) {
        try {
            final Field field = Typeface.class.getDeclaredField("sSystemFontMap");
            field.setAccessible(true);
            Map<String, Typeface> oldFonts = (Map<String, Typeface>) field.get(null);
            if (oldFonts != null) {
                oldFonts.putAll(typefaces);
            } else {
                oldFonts = typefaces;
            }
            field.set(null, oldFonts);
            field.setAccessible(false);
        } catch (Exception e) {
            Log.e("TypefaceUtil", "Can not set custom fonts");
        }
    }

    public static Typeface getTypeface(int fontType, Context context) {
        // here you can load the Typeface from asset or use default ones
        switch (fontType) {
            case BOLD:
                return Typeface.create(SANS_SERIF, Typeface.BOLD);
            case ITALIC:
                return Typeface.create(SANS_SERIF, Typeface.ITALIC);
            case BOLD_ITALIC:
                return Typeface.create(SANS_SERIF, Typeface.BOLD_ITALIC);
            case LIGHT:
                return Typeface.create(SANS_SERIF_LIGHT, Typeface.NORMAL);
            case CONDENSED:
                return Typeface.create(SANS_SERIF_CONDENSED, Typeface.NORMAL);
            case THIN:
                return Typeface.create(SANS_SERIF_MEDIUM, Typeface.NORMAL);
            case MEDIUM:
                return Typeface.create(SANS_SERIF_THIN, Typeface.NORMAL);
            case REGULAR:
            default:
                return Typeface.create(SANS_SERIF, Typeface.NORMAL);
        }
    }
}

затем, когда вы захотите переопределить шрифты, вы можете просто вызвать метод и присвоить ему карту шрифтов следующим образом:

Typeface regular = TypefaceUtil.getTypeface(REGULAR, context);
Typeface light = TypefaceUtil.getTypeface(REGULAR, context);
Typeface condensed = TypefaceUtil.getTypeface(CONDENSED, context);
Typeface thin = TypefaceUtil.getTypeface(THIN, context);
Typeface medium = TypefaceUtil.getTypeface(MEDIUM, context);
Map<String, Typeface> fonts = new HashMap<>();
fonts.put("sans-serif", regular);
fonts.put("sans-serif-light", light);
fonts.put("sans-serif-condensed", condensed);
fonts.put("sans-serif-thin", thin);
fonts.put("sans-serif-medium", medium);
TypefaceUtil.overrideFonts(fonts);

для полной проверки примера

Это работает только для Android SDK 21 и выше, для более ранних версий проверьте полный пример

Исмаил Альметвалли
источник
5

Просто используйте эту библиотеку, скомпилируйте ее в свой файл оценок

complie'me.anwarshahriar:calligrapher:1.0'

и использовать его в методе onCreate в основной деятельности

Calligrapher calligrapher = new Calligrapher(this);
calligrapher.setFont(this, "yourCustomFontHere.ttf", true);

Это самый элегантный супер быстрый способ сделать это.

Мохамед Айед
источник
2

Это работа для моего проекта, источник https://gist.github.com/artem-zinnatullin/7749076

Создайте каталог шрифтов внутри папки активов, а затем скопируйте свой собственный шрифт в каталог шрифтов, например, я использую trebuchet.ttf;

Создать класс TypefaceUtil.java;

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

import java.lang.reflect.Field;
public class TypefaceUtil {

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

        }
    }
}

Изменить тему в файле styles.xml добавить ниже

<item name="android:typeface">serif</item>

Пример в Моем styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:typeface">serif</item><!-- Add here -->
    </style>


    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowActionBarOverlay">true</item>
        <item name="android:windowFullscreen">true</item>
    </style>
</resources>

Наконец, в Activity или Fragment onCreate вызовите TypefaceUtil.java

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TypefaceUtil.overrideFont(getContext(), "SERIF", "fonts/trebuchet.ttf");
    }
Ирван Дви Пангга
источник
0

Android не предоставляет много способов поддержки применения шрифтов ко всему приложению (см. Эту проблему ). У вас есть 4 варианта установки шрифта для всего приложения:

  • Вариант 1. Применение отражения для изменения системного шрифта.
  • Вариант 2. Создание и создание подклассов пользовательских классов View для каждого View, для которого требуется собственный шрифт.
  • Вариант 3. Реализуйте View Crawler, который просматривает иерархию представления для текущего экрана.
  • Вариант 4. Использование сторонней библиотеки.

Подробности этих опций можно найти здесь .

Phileo99
источник
0

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

public static void setFont(ViewGroup layout)
{
    final int childcount = layout.getChildCount();
    for (int i = 0; i < childcount; i++)
    {
        // Get the view
        View v = layout.getChildAt(i);

        // Apply the font to a possible TextView
        try {
            ((TextView) v).setTypeface(MY_CUSTOM_FONT);
            continue;
        }
        catch (Exception e) { }

        // Apply the font to a possible EditText
        try {
            ((TextView) v).setTypeface(MY_CUSTOM_FONT);
            continue;
        }
        catch (Exception e) { }

        // Recursively cicle into a possible child layout
        try {
            ViewGroup vg = (ViewGroup) v;
            Utility.setFont(vg);
            continue;
        }
        catch (Exception e) { }
    }
}
FonzTech
источник
0

чтобы просто набор начертания приложения к normal, sans, serifилиmonospace (не пользовательский шрифт!), вы можете сделать это.

определите тему и установите android:typefaceатрибут для гарнитуры, которую вы хотите использовать styles.xml:

<resources>

    <!-- custom normal activity theme -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <!-- other elements -->
        <item name="android:typeface">monospace</item>
    </style>

</resources>

применить тему ко всему приложению в AndroidManifest.xmlфайле:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application
        android:theme="@style/AppTheme" >
    </application>
</manifest>

Ссылка на Android

Эрик
источник
Вы уверены, что это работает? Согласно документу Android: «Должно быть одно из следующих постоянных значений: нормальное, без засечек, с засечками, моноширинный».
Tomrozb
1
О, я понимаю ... ты прав ... я не понял вопроса в конце концов: x Я просто хотел, чтобы все мое приложение использовало моноширинный шрифт (не пользовательский), и я увидел, что оно работает, поэтому я опубликовал это здесь ......... я думаю, что мой ответ все еще может быть полезен для других, кто хочет сделать что-то подобное .... поэтому я отредактирую это и оставлю это здесь ..... я в порядке, не так ли накапливает голоса вниз. спасибо за указание на это
Eric
Эй, @Dave Cruise, это работает только для моно-пространства? Я проверил его только для монокосмического пространства ... и ничего больше .... так что я не уверен ... но согласно документации, он должен работать и для "нормальных", "без" и "засечек" .. Я думаю, что шрифт более общий, чем шрифт, поэтому мы не можем использовать его для установки шрифта приложения на определенный шрифт, например «consolas» или что-то в этом роде.
Эрик
@ Эрик да. я тоже понятия не имею моноспейс работает как шарм, но не везет для нормальных, без засечек.
Дейв Круз
0

Попробуйте эту библиотеку, ее легкий и простой в реализации

https://github.com/sunnag7/FontStyler

<com.sunnag.fontstyler.FontStylerView
              android:textStyle="bold"
              android:text="@string/about_us"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:paddingTop="8dp"
              app:fontName="Lato-Bold"
              android:textSize="18sp"
              android:id="@+id/textView64" />
Санни Нагвекер
источник
-7

Ответ - нет, вы не можете. См. Можно ли установить собственный шрифт для всего приложения? Чтобы получить больше информации.

Есть обходные пути, но ничего в строках «одной строки кода здесь и все мои шрифты не будут это вместо того , чтобы ».

(Я вроде благодарю Google и Apple за это). У пользовательских шрифтов есть место, но если их легко заменить во всем приложении, это создаст целый мир приложений Comic Sans )

Мартин Маркончини
источник
41
Полностью не согласен с вашим комментарием. Глобальная настройка шрифта должна быть тривиальной задачей, а не то, что требует необходимых обходных путей. Разработчики / дизайнеры всего мира должны избегать приложений «Comic Sans», а не Google / Apple, чтобы обеспечить это.
LocalPCGuy
4
Согласованность> Необычный дизайн.
Мартин Маркончини
14
Однако консистенция <функциональность. Мы разрабатываем приложения, которые отображают библейский иврит. Все стандартные шрифты, найденные на устройствах Android (включая новейшие шрифты Android L), выполняют ужасную работу по отрисовке знаков кантилляции (и, между прочим, они выполняют посредственную работу над гласными знаками, хотя и становятся лучше). Нам абсолютно необходимо использовать собственный шрифт во всем приложении, и нам пришлось писать слишком много кода, чтобы просто получить все необходимые представления, используя его.
Тед Хопп