Можно ли установить собственный шрифт для всего приложения? - PullRequest
261 голосов
/ 26 апреля 2010

Мне нужно использовать определенный шрифт для всего приложения. У меня есть файл .ttf для того же. Можно ли установить его в качестве шрифта по умолчанию при запуске приложения, а затем использовать его в другом месте приложения? Когда установлено, как я могу использовать его в XML-макете?

Ответы [ 24 ]

6 голосов
/ 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:

<style name="Theme.Storehouse" parent="Theme.Sherlock">
    <item name="android:typeface">monospace</item>
</style>
4 голосов
/ 12 марта 2015

Вы можете установить пользовательские шрифты для каждого макета один за другим, с помощью всего одного вызова функции из каждого макета, передав его корневой View.First, создайте подход singelton для доступа к объекту шрифта, как этот

 public class Font {
    private static Font font;
    public Typeface ROBO_LIGHT;

    private Font() {

    }

    public static Font getInstance(Context context) {
        if (font == null) {
            font = new Font();
            font.init(context);
        }
        return font;

    }

    public void init(Context context) {

        ROBO_LIGHT = Typeface.createFromAsset(context.getAssets(),
                "Roboto-Light.ttf");
    }

}

Вы можете определить различные шрифты в вышеприведенном классе. Теперь определите класс Helper для шрифтов, который будет применять шрифты:

   public class FontHelper {

    private static Font font;

    public static void applyFont(View parentView, Context context) {

        font = Font.getInstance(context);

        apply((ViewGroup)parentView);

    }

    private static void apply(ViewGroup parentView) {
        for (int i = 0; i < parentView.getChildCount(); i++) {

            View view = parentView.getChildAt(i);

//You can add any view element here on which you want to apply font 

            if (view instanceof EditText) {

                ((EditText) view).setTypeface(font.ROBO_LIGHT);

            }
            if (view instanceof TextView) {

                ((TextView) view).setTypeface(font.ROBO_LIGHT);

            }

            else if (view instanceof ViewGroup
                    && ((ViewGroup) view).getChildCount() > 0) {
                apply((ViewGroup) view);
            }

        }

    }

}

В приведенном выше коде я применяю шрифты только к textView и EditText, вы также можете применять шрифты и к другим элементам представления. Вам просто нужно передать идентификатор вашей корневой группы представления вышеописанному методу применения шрифта. например, ваш макет:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/mainParent"
    tools:context="${relativePackage}.${activityClass}" >

    <RelativeLayout
        android:id="@+id/mainContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/homeFooter"
        android:layout_below="@+id/edit" >

        <ImageView
            android:id="@+id/PreviewImg"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/abc_list_longpressed_holo"
            android:visibility="gone" />

        <RelativeLayout
            android:id="@+id/visibilityLayer"
            android:layout_width="match_parent"
            android:layout_height="fill_parent" >

            <ImageView
                android:id="@+id/UseCamera"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerHorizontal="true"
                android:src="@drawable/camera" />

            <TextView
                android:id="@+id/tvOR"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/UseCamera"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="20dp"
                android:text="OR"
                android:textSize="30dp" />

            <TextView
                android:id="@+id/tvAND"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="20dp"
                android:text="OR"
                android:textSize="30dp" />

</RelativeLayout>

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

public class MainActivity extends BaseFragmentActivity {

    private EditText etName;
    private EditText etPassword;
    private TextView tvTitle;
    public static boolean isHome = false;

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

       Font font=Font.getInstance(getApplicationContext());
        FontHelper.applyFont(findViewById(R.id.mainParent),          getApplicationContext());
   }    
}

Ура :)

3 голосов
/ 08 марта 2012

Я бы предложил расширить TextView и всегда использовать ваш собственный TextView в макетах XML или там, где вам нужен TextView. В вашем пользовательском TextView переопределите setTypeface

@Override
public void setTypeface(Typeface tf, int style) {
    //to handle bold, you could also handle italic or other styles here as well
    if (style == 1){
        tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans700.otf");
    }else{
        tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans500.otf");
    }
    super.setTypeface(tf, 0);
}
2 голосов
/ 16 сентября 2013

Решение Тома прекрасно работает, но работает только с TextView и EditText.

Если вы хотите охватить большинство видов (RadioGroup, TextView, Checkbox ...), я создал метод, который делает это:

protected void changeChildrenFont(ViewGroup v, Typeface font){
    for(int i = 0; i < v.getChildCount(); i++){

        // For the ViewGroup, we'll have to use recursivity
        if(v.getChildAt(i) instanceof ViewGroup){
            changeChildrenFont((ViewGroup) v.getChildAt(i), font);
        }
        else{
            try {
                Object[] nullArgs = null;
                //Test wether setTypeface and getTypeface methods exists
                Method methodTypeFace = v.getChildAt(i).getClass().getMethod("setTypeface", new Class[] {Typeface.class, Integer.TYPE});
                //With getTypefaca we'll get back the style (Bold, Italic...) set in XML
                Method methodGetTypeFace = v.getChildAt(i).getClass().getMethod("getTypeface", new Class[] {});
                Typeface typeFace = ((Typeface)methodGetTypeFace.invoke(v.getChildAt(i), nullArgs));
                //Invoke the method and apply the new font with the defined style to the view if the method exists (textview,...)
                methodTypeFace.invoke(v.getChildAt(i), new Object[] {font, typeFace == null ? 0 : typeFace.getStyle()});
            }
            //Will catch the view with no such methods (listview...)
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Этот метод возвращает стиль представления, заданный в XML (жирный, курсив ...), и применяет их, если они существуют.

Для ListView я всегда создаю адаптер и устанавливаю шрифт внутри getView.

2 голосов
/ 08 мая 2015

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

public final class TypefaceAssigner {

public final Typeface DEFAULT;
public final Typeface DEFAULT_BOLD;

@Inject
public TypefaceAssigner(AssetManager assetManager) {
    DEFAULT = Typeface.createFromAsset(assetManager, "TradeGothicLTCom.ttf");
    DEFAULT_BOLD = Typeface.createFromAsset(assetManager, "TradeGothicLTCom-Bd2.ttf");
}

public void assignTypeface(View v) {
    if (v instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) v).getChildCount(); i++) {
            View view = ((ViewGroup) v).getChildAt(i);
            if (view instanceof ViewGroup) {
                setTypeface(view);
            } else {
                setTypeface(view);
            }
        }
    } else {
        setTypeface(v);
    }
}

private void setTypeface(View view) {
    if (view instanceof TextView) {
        TextView textView = (TextView) view;
        Typeface typeface = textView.getTypeface();
        if (typeface != null && typeface.isBold()) {
            textView.setTypeface(DEFAULT_BOLD);
        } else {
            textView.setTypeface(DEFAULT);
        }
    }
}
}

Теперь во всех фрагментах в onViewCreated или onCreateView, во всех действиях в onCreate и во всех адаптерах представления в getView или newView просто вызовите:

typefaceAssigner.assignTypeface(view);
1 голос
/ 21 ноября 2017

в API 26 с build.gradle 3.0.0 и выше, вы можете создать каталог шрифтов в res и использовать эту строку в своем стиле

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

для изменения build.gradle используйте это в вашей сборке.Зависимости gradle

classpath 'com.android.tools.build:gradle:3.0.0'
1 голос
/ 20 января 2018

Наконец, Google осознал серьезность этой проблемы (применяя нестандартный шрифт к компонентам пользовательского интерфейса) и разработал для нее чистое решение.

Сначала вам нужно выполнить обновление для поддержки библиотеки 26+ (вам также может понадобиться обновить ваш gradle {4.0+}, android studio), затем вы можете создать новую папку ресурсов с именем font. В эту папку вы можете поместить ресурсы шрифта (.tff, ...). Затем вам нужно переопределить приложение по умолчанию их и заставить свой собственный шрифт в нем:)

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:fontFamily">@font/my_custom_font</item>
</style>

Примечание: если вы хотите поддерживать устройства с более старым API, чем 16, вы должны использовать пространство имен приложения вместо Android!

0 голосов
/ 08 апреля 2015

Я также хотел бы улучшить ответ Уэстона на API 21 Android 5.0.

У меня была такая же проблема на моем Samsung s5 при использовании шрифта DEFAULT. (с другими шрифтами работает нормально)

Мне удалось заставить его работать, задав гарнитуру (например, "sans") в файлах XML для каждого Textview или кнопки

<TextView
android:layout_width="match_parent"
android:layout_height="39dp"
android:textColor="@color/abs__background_holo_light"
android:textSize="12sp"
android:gravity="bottom|center"
android:typeface="sans" />

и в классе MyApplication:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
    TypefaceUtil.overrideFont(getApplicationContext(), "SANS_SERIF",
    "fonts/my_font.ttf");
    }
}

Надеюсь, это поможет.

0 голосов
/ 18 октября 2016
package com.theeasylearn.demo.designdemo;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;

public class MyButton extends TextView {

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

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

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

    private void init() {

            Typeface tf =
                    Typeface.createFromAsset(
                            getContext().getAssets(), "angelina.TTF");
            setTypeface(tf);

    }

}
0 голосов
/ 06 октября 2016

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

Итак, я попробовал Fontain , который позволяет вам определять пользовательские виды и применять их к семействам пользовательских шрифтов.

чтобы использовать Fontain, вы должны добавить в свой модуль приложения build.gradle следующее:

compile 'com.scopely:fontain:1.0.0'

Тогда вместо обычного TextView вы должны использовать FontTextView

Пример FontTextView с заглавными и жирными буквами:

 <com.scopely.fontain.views.FontTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/black"
            android:textColor="@android:color/white"
            android:textSize="11dp"
            android:gravity="center"
            android:id="@+id/tv1"
            app:font_family="myCustomFont"
            app:caps_mode="characters"
            app:font_weight="BOLD"/>
...