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

111

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

Так,

  • Есть ли способ сделать это из XML? [Установка собственного шрифта]
  • Есть ли способ сделать это из кода в одном месте, чтобы сказать, что все приложение и все компоненты должны использовать настраиваемый шрифт вместо шрифта по умолчанию?
Codevalley
источник
stackoverflow.com/questions/5541058/… Посмотрите этот пост. Я разместил здесь полный код по этой проблеме
Маниш Сингла
Вы можете использовать статические переменные в своей основной деятельности для хранения ссылок на встроенные шрифты. Это приведет к тому, что будет один постоянный набор шрифтов, который не подберет GC.
Jacksonkr 02
Заводской способ. Или метод, который учитывает ваше мнение и устанавливает все настройки шрифта и гарнитуры.
mtmurdock
Новая библиотека поддержки 26 теперь позволяет использовать шрифты в XML. Вот как это сделать Шрифты в XML
Винисиус Сильва

Ответы:

80

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

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

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

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

В настоящее время для них существует множество вариантов:

  • Ресурсы шрифтов и резервные копии в Android SDK, если вы используете appcompat

  • Сторонние библиотеки для тех, кто не использует appcompat, хотя не все будут поддерживать определение шрифта в ресурсах макета.

CommonsWare
источник
4
@Codevalley: Ну, во многих отношениях лучший ответ - не возиться с пользовательскими шрифтами. Они, как правило, большие, что увеличивает количество загрузок и сокращает количество людей, которые будут загружать и продолжать использовать ваше приложение.
CommonsWare 05
22
@CommonsWare: я не обязательно согласен. Шрифт является неотъемлемой частью стиля пользовательского интерфейса, как и фоновые изображения и т. Д. И размер не всегда бывает большим. Например, шрифт в моем случае всего 19,6 КБ :)
Codevalley 06
2
@Amit: В этом вопросе не было никаких изменений. Существует множество фрагментов кода, которые помогают упростить применение шрифта к пользовательскому интерфейсу на Java, но нет способа сделать это из XML.
CommonsWare
1
@Amit: «Но означает ли это, что мне придется создавать свои собственные файлы .ttf или .otf для пользовательских шрифтов?» - гм, нет. Вы можете использовать существующие шрифты TTF / OTF, хотя не все они могут работать. Проблема в этом вопросе заключается в том, как применить эти шрифты во всем приложении, что по-прежнему невозможно, и именно об этом я говорил в своем комментарии.
CommonsWare
1
Этот принятый ответ устарел, и было бы здорово его обновить или удалить.
Sky Kelsey
109

Да, это возможно.

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

В 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где требуется такая же возможность.
CommonsWare 09
Привет, Маниш, спасибо за решение. Хотя я столкнулся с проблемой при использовании этого. Я продолжаю получать «не найден идентификатор ресурса для атрибута ttf_name в пакете com.lht.android»
Кшитий Аггарвал
17
Это будет работать, но до ICS он будет выделять память для шрифтов для каждого создаваемого вами представления: code.google.com/p/android/issues/detail?id=9904 Способ исправить это - создать глобально доступный статическая хэш-карта всех созданных шрифтов: code.google.com/p/android/issues/detail?id=9904#c7
Ken Van Hoeylandt,
Зачем нам цикл? Разве он не работает с одним вызовом?
Гильермо Тобар,
1
@AlaksiejN. в случае, если вам нужно установить разные гарнитуры для разных TextView ...
Ник,
49

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

Проверено на 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.

Пер Кристиан Хенден
источник
Для меня это лучшее решение.
Igor K
2
по умолчанию у меня не работает. если я использую моноширинный codeшрифт, а затем устанавливаю <style name = "AppTheme" parent = "AppBaseTheme"> <item name = "android: typeface"> моноширинный </item> </style>, codeон работает, но не для жирного шрифта. я добавил этот код в класс, расширяющий Application. это правильное место? @ P-chan
Кристофер Ривера
2
@ChristopherRivera Да, добавьте его в класс Application вашего приложения, убедитесь, что он работает на onCreate. Взглянув на grepcode.com/file/repository.grepcode.com/java/ext/ ... Я бы посоветовал вам переопределить дополнительное поле для моноширинного режима, а также поле в моем примере кода выше!
Пер Кристиан Хенден,
2
Хорошо, я поменял поле на SERIF, и это сработало :)
Абдулла Умер
3
Этот ответ ссылается на этот ответ и обеспечивает более чистый подход imho.
adamdport
36

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

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

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

Pospi
источник
Довольно много. В то время это был единственный способ сделать это в сроки проекта. Удобный ярлык при необходимости (:
pospi
23

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

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

У меня есть следующее, 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"));
}
}

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

My 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;
}
}
M-WaJeEh
источник
2
Это должно получить больше голосов. Он работает, и у него есть снимок экрана для демонстрации
Эрикн
10

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

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

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

Гарнитура String представляет xyz.ttf в папке с ресурсами. (я создал класс констант) Теперь вы можете использовать его везде в своем приложении:

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

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

Informatic0re
источник
4

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

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

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);
Majinboo
источник
4

Я нашел хорошее решение в блоге Лизы Рэй . С новой привязкой данных можно установить шрифт в ваших файлах 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"/>
userM1433372
источник
Вы можете предложить пример использования привязки данных? Это было бы очень признательно.
Шри Кришна
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;
        }
    }

}
Snicolas
источник
2

Реализации LayoutInflater по умолчанию не поддерживают указание гарнитуры шрифта из xml. Однако я видел, как это было сделано в xml, предоставив настраиваемую фабрику для 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

Установка пользовательского шрифта на обычный 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);
artProc
источник
1

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

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

Амрута-Пани
источник
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: поле помечено как 'final' в java.lang.reflect.Field.setField (собственный метод) в java.lang.reflect.Field.set (Field.java: 556)
Совет директоров
0

Мне нравится предложение Поспи. Почему бы не сделать все возможное, используя свойство '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, «вырезана» по-гречески! Какого черта...?

Ричард
источник
0

Ответ @ 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

Работа для 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

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

Mohale
источник
0

Может быть полезно знать, что начиная с 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

Используйте атрибут fontPath непосредственно в XML-файле.

для использования в style.xml

<item name = "fontPath"> шрифты / ProximaNovaSemibold.ttf </item>

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

fontPath = "шрифты / ProximaNovaBold.ttf"

(Примечание: нет необходимости использовать атрибут app / android в префиксе)

Dharmendra
источник
-6

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

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