it-roy-ru.com

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

Я добавил файл пользовательских шрифтов в папку assets/fonts. Как мне использовать это из моего XML? 

Я могу использовать его из кода следующим образом:

TextView text = (TextView) findViewById(R.id.textview03);
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Molot.otf");
text.setTypeface(tf);

Разве я не могу сделать это из XML с помощью атрибута Android:typeface="/fonts/Molot.otf"?

90
npanigrahy

Краткий ответ: Нет. Android не имеет встроенной поддержки для применения пользовательских шрифтов к текстовым виджетам через XML.

Однако есть обходной путь, который не очень сложно реализовать.

Первый

Вам нужно определить свой собственный стиль. В папке/res/values ​​откройте/создайте файл attrs.xml и добавьте объект, который может быть объявлен как:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FontText">
        <attr name="typefaceAsset" format="string"/>
    </declare-styleable>
</resources>

Второй

Предполагая, что вы хотите часто использовать этот виджет, вы должны настроить простой кэш для загруженных объектов Typeface, так как загрузка их из памяти на лету может занять некоторое время. Что-то вроде:

public class FontManager {
    private static FontManager instance;

    private AssetManager mgr;

    private Map<String, Typeface> fonts;

    private FontManager(AssetManager _mgr) {
        mgr = _mgr;
        fonts = new HashMap<String, Typeface>();
    }

    public static void init(AssetManager mgr) {
        instance = new FontManager(mgr);
    }

    public static FontManager getInstance() {
        if (instance == null) {
            // App.getContext() is just one way to get a Context here
            // getContext() is just a method in an Application subclass
            // that returns the application context
            AssetManager assetManager = App.getContext().getAssets();
            init(assetManager);
        }
        return instance;
    }

    public Typeface getFont(String asset) {
        if (fonts.containsKey(asset))
            return fonts.get(asset);

        Typeface font = null;

        try {
            font = Typeface.createFromAsset(mgr, asset);
            fonts.put(asset, font);
        } catch (Exception e) {

        }

        if (font == null) {
            try {
                String fixedAsset = fixAssetFilename(asset);
                font = Typeface.createFromAsset(mgr, fixedAsset);
                fonts.put(asset, font);
                fonts.put(fixedAsset, font);
            } catch (Exception e) {

            }
        }

        return font;
    }

    private String fixAssetFilename(String asset) {
        // Empty font filename?
        // Just return it. We can't help.
        if (TextUtils.isEmpty(asset))
            return asset;

        // Make sure that the font ends in '.ttf' or '.ttc'
        if ((!asset.endsWith(".ttf")) && (!asset.endsWith(".ttc")))
            asset = String.format("%s.ttf", asset);

        return asset;
    }
}

Этот позволит вам использовать расширения файла .ttc, но он не проверен.

В третьих

Создайте новый класс, который подклассы TextView. Этот конкретный пример учитывает определенный шрифт XML (bold, italic и т.д.) И применяет его к шрифту (при условии, что вы используете файл .ttc).

/**
 * TextView subclass which allows the user to define a truetype font file to use as the view's typeface.
 */
public class FontText extends TextView {
    public FontText(Context context) {
        this(context, null);
    }

    public FontText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FontText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        if (isInEditMode())
            return;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.FontText);

        if (ta != null) {
            String fontAsset = ta.getString(R.styleable.FontText_typefaceAsset);

            if (!TextUtils.isEmpty(fontAsset)) {
                Typeface tf = FontManager.getInstance().getFont(fontAsset);
                int style = Typeface.NORMAL;
                float size = getTextSize();

                if (getTypeface() != null)
                    style = getTypeface().getStyle();

                if (tf != null)
                    setTypeface(tf, style);
                else
                    Log.d("FontText", String.format("Could not create a font from asset: %s", fontAsset));
            }
        }
    }
}

В заключение

Замените экземпляры TextView в вашем XML полным именем класса. Объявите свое собственное пространство имен так же, как и пространство имен Android. Обратите внимание, что «typefaceAsset» должен указывать на файл .ttf или .ttc, содержащийся в каталоге/assets.

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:custom="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <com.example.FontText
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="This is a custom font text"
        custom:typefaceAsset="fonts/AvenirNext-Regular.ttf"/>
</RelativeLayout>
43
themarshal

Вот пример кода, который делает это. У меня есть шрифт, определенный в статической переменной final, а файл шрифта находится в каталоге assets.

public class TextViewWithFont extends TextView {

    public TextViewWithFont(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setTypeface(MainActivity.typeface);
    }

    public TextViewWithFont(Context context) {
        super(context);
        this.setTypeface(MainActivity.typeface);
    }

}
27
Stephan Wiesner

Упражнение реализует LayoutInflater.Factory2, который предоставляет обратные вызовы для каждого созданного представления .... Возможно стилизовать TextView с атрибутом семейства пользовательских шрифтов, загрузить шрифты по требованию и автоматически вызывать setTypeface для экземпляров текста.

К сожалению, из-за архитектурной взаимосвязи экземпляров Inflater относительно Activity и Windows самый простой подход к использованию пользовательских шрифтов в Android - это кэширование загруженных шрифтов на уровне приложения.

Пример базы кода здесь:

https://github.com/leok7v/Android-textview-custom-fonts

  <style name="Baroque" parent="@Android:style/TextAppearance.Medium">
    <item name="Android:layout_width">fill_parent</item>
    <item name="Android:layout_height">wrap_content</item>
    <item name="Android:textColor">#F2BAD0</item>
    <item name="Android:textSize">14pt</item>
    <item name="fontFamily">baroque_script</item>
  </style>

  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
          xmlns:custom="http://schemas.Android.com/apk/res/custom.fonts"
          Android:orientation="vertical"
          Android:layout_width="fill_parent"
          Android:layout_height="fill_parent"
  >
  <TextView
    style="@style/Baroque"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    Android:text="@string/sample_text"
  />

результаты в

enter image description here

11
Leo

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

public class HeliVnTextView extends TextView {

/*
 * Caches typefaces based on their file path and name, so that they don't have to be created every time when they are referenced.
 */
private static Typeface mTypeface;

public HeliVnTextView(final Context context) {
    this(context, null);
}

public HeliVnTextView(final Context context, final AttributeSet attrs) {
    this(context, attrs, 0);
}

public HeliVnTextView(final Context context, final AttributeSet attrs, final int defStyle) {
    super(context, attrs, defStyle);

     if (mTypeface == null) {
         mTypeface = Typeface.createFromAsset(context.getAssets(), "HelveticaiDesignVnLt.ttf");
     }
     setTypeface(mTypeface);
}

}

В XML-файле:

<Java.example.HeliVnTextView
        Android:id="@+id/textView1"
        Android:layout_width="0dp"
        ... />

В классе Java:

HeliVnTextView title = new HeliVnTextView(getActivity());
title.setText(issue.getName());
11
haotang

ОБНОВЛЕНИЕ: https://github.com/chrisjenx/Calligraphy представляется превосходное решение для этого.


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

Мне удалось добавить свой пользовательский шрифт в список системных шрифтов с собственным именем семейства шрифтов, а затем указать это имя семейства пользовательских шрифтов ("brush-script") в качестве значения Android: FontFamily в стандартном TextView. работал на моем LG G4 под управлением Android 6.0.

public class MyApplication extends Android.app.Application
{
    @Override
    public void onCreate()
    {
        super.onCreate();

        Typeface font = Typeface.createFromAsset(this.getResources().getAssets(),"fonts/brush-script.ttf");
        injectTypeface("brush-script", font);
    }

    private boolean injectTypeface(String fontFamily, Typeface typeface)
    {
        try
        {
            Field field = Typeface.class.getDeclaredField("sSystemFontMap");
            field.setAccessible(true);
            Object fieldValue = field.get(null);
            Map<String, Typeface> map = (Map<String, Typeface>) fieldValue;
            map.put(fontFamily, typeface);
            return true;
        }
        catch (Exception e)
        {
            Log.e("Font-Injection", "Failed to inject typeface.", e);
        }
        return false;
    }
}

В моем макете

<TextView
    Android:id="@+id/name"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="Fancy Text"
    Android:fontFamily="brush-script"/>
7
Ross Bradbury

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

7
type-a1pha

Я знаю, что это старый вопрос, но я нашел гораздо более простое решение.

Сначала объявите ваш TextView в xml как обычно .. Поместите ваш шрифт (TTF или TTC) в папку ресурсов

приложение\SRC\основные\активы \

Затем просто установите шрифт для вашего текстового представления в вашем методе onCreate.

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

    TextView textView = findViewById(R.id.my_textView);
    Typeface typeface = Typeface.createFromAsset(getAssets(), "fontName.ttf");
    textView.setTypeface(typeface);
}

Готово.

3
Oiproks

Создайте папку шрифтов в ресурсах и добавьте туда все необходимые шрифты.

public class CustomTextView extends TextView {
    private static final String TAG = "TextView";

    public CustomTextView(Context context) {
        super(context);
    }

    public CustomTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setCustomFont(context, attrs);
    }

    public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }

    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
        String customFont = a.getString(R.styleable.CustomTextView_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }

    public boolean setCustomFont(Context ctx, String fontName) {
        Typeface typeface = null;
        try {
            if(fontName == null){
                fontName = Constants.DEFAULT_FONT_NAME;
            }
            typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/" + fontName);
        } catch (Exception e) {
            Log.e(TAG, "Unable to load typeface: "+e.getMessage());
            return false;
        }
        setTypeface(typeface);
        return true;
    }
}

и добавить декларируемое в attrs.xml

<declare-styleable name="CustomTextView">
      <attr name="customFont" format="string"/>
</declare-styleable>

а затем добавить свой пользовательский шрифт, как

app:customFont="arial.ttf"
1
Xar E Ahmer

Лучшее решение - использовать (наконец-то) введенную Google встроенную функцию нестандартного шрифта в XML. Но вы должны ориентироваться на API 26. Он поддерживает API 16+

https://developer.Android.com/guide/topics/ui/look-and-feel/fonts-in-xml

0
Kirill Karmazin

вместо xmlns: custom = "schemas.Android.com/tools"; вы должны использовать: xmlns: custom = "schemas.Android.com/apk/res-auto"; для того, чтобы использовать настраиваемые атрибуты . Я сделал это изменение, и оно работает сейчас. 

0
Abhinav Saxena