Использование пользовательского шрифта в android TextView с помощью xml
Я добавил файл пользовательских шрифтов в папку my 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"
?
Ответы
Ответ 1
Короткий ответ: Нет. 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 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>
Ответ 2
Вот пример кода, который делает это. У меня есть шрифт, определенный в статической конечной переменной, а файл шрифта находится в каталоге ресурсов.
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);
}
}
Ответ 3
Действие реализует LayoutInflater.Factory2, который обеспечивает обратные вызовы для каждого созданного Просмотра.
Можно стилизовать TextView с помощью специального атрибута fontFamily, загружать шрифты по требованию и автоматически вызывать setTypeface при создании экземпляров автоматически.
К сожалению, из-за архитектурных отношений экземпляров Inflater относительно действий и Windows самый простой подход заключается в кэшировании загруженных шрифтов на уровне приложения.
База кода примера находится здесь:
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]()
Ответ 4
Создайте свой собственный TextView для шрифта, который вы хотите использовать. В этом классе я использую статическое поле mTypeface для кэширования Typeface (для лучшей производительности)
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());
Ответ 5
Не рекомендуется использовать пользовательские шрифты в xml из-за этот факт
то есть вы должны делать это программно, чтобы избежать утечки памяти!
Ответ 6
UPDATE: 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
Я знаю, что это старый вопрос, но я нашел гораздо более легкое решение.
Сначала объявите свой 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);
}
Готово.
Ответ 8
вместо xmlns: custom = "schemas.android.com/tools"; вы должны использовать: xmlns: custom = "schemas.android.com/apk/res-auto"; чтобы использовать атрибуты стиля.
Я сделал это изменение, и он работает сейчас.
Ответ 9
Создайте папку шрифтов в активах и добавьте там все необходимые шрифты.
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>
а затем добавьте свой customFont, например
app:customFont="arial.ttf"