Пользовательские шрифты и XML-макеты (Android)
Я пытаюсь определить макет графического интерфейса с использованием файлов XML в Android. Насколько я могу судить, нет способа указать, что ваши виджеты должны использовать пользовательский шрифт (например, тот, который вы разместили в файле/шрифте/) в файлах XML, и вы можете использовать только установленные системой шрифты.
Я знаю, что в коде Java я могу вручную изменить шрифт каждого виджета, используя уникальные идентификаторы. В качестве альтернативы я мог бы перебирать все виджеты на Java, чтобы сделать это изменение, но это, вероятно, будет очень медленным.
Какие еще варианты у меня есть? Есть ли какие-либо более эффективные способы создания виджетов, имеющих пользовательский вид? Я не особо хочу, чтобы вручную менять шрифт для каждого нового добавляемого виджета.
Ответы
Ответ 1
Вы можете расширить TextView для установки пользовательских шрифтов, как я узнал здесь.
TextViewPlus.java:
package com.example;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
public class TextViewPlus extends TextView {
private static final String TAG = "TextView";
public TextViewPlus(Context context) {
super(context);
}
public TextViewPlus(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public TextViewPlus(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.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
Log.e(TAG, "Could not get typeface: "+e.getMessage());
return false;
}
setTypeface(tf);
return true;
}
}
attrs.xml: (в res/values)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TextViewPlus">
<attr name="customFont" format="string"/>
</declare-styleable>
</resources>
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:foo="http://schemas.android.com/apk/res/com.example"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.example.TextViewPlus
android:id="@+id/textViewPlus1"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:text="@string/showingOffTheNewTypeface"
foo:customFont="saxmono.ttf">
</com.example.TextViewPlus>
</LinearLayout>
Вы должны поместить "saxmono.ttf" в папку с ресурсами.
ОБНОВЛЕНИЕ 8/1/13
С этим методом возникают серьезные проблемы с памятью. См. комментарий chedabob ниже.
Ответ 2
Я опаздываю на вечеринку на 3 года:( Однако это может быть полезно для тех, кто может наткнуться на этот пост.
Я написал библиотеку, которая кэширует Typefaces, а также позволяет указать пользовательские шрифты прямо из XML. Вы можете найти библиотеку здесь.
Вот как выглядит ваш XML-макет при его использовании.
<com.mobsandgeeks.ui.TypefaceTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
geekui:customTypeface="fonts/custom_font.ttf" />
Ответ 3
Это может быть немного поздно, но вам нужно создать одноэлементный класс, который возвращает пользовательский шрифт, чтобы избежать утечек памяти.
Класс TypeFace:
public class OpenSans {
private static OpenSans instance;
private static Typeface typeface;
public static OpenSans getInstance(Context context) {
synchronized (OpenSans.class) {
if (instance == null) {
instance = new OpenSans();
typeface = Typeface.createFromAsset(context.getResources().getAssets(), "open_sans.ttf");
}
return instance;
}
}
public Typeface getTypeFace() {
return typeface;
}
}
Пользовательский TextView:
public class NativelyCustomTextView extends TextView {
public NativelyCustomTextView(Context context) {
super(context);
setTypeface(OpenSans.getInstance(context).getTypeFace());
}
public NativelyCustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setTypeface(OpenSans.getInstance(context).getTypeFace());
}
public NativelyCustomTextView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setTypeface(OpenSans.getInstance(context).getTypeFace());
}
}
По xml:
<com.yourpackage.views.NativelyCustomTextView
android:id="@+id/natively_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="20dp"
android:text="@string/natively"
android:textSize="30sp" />
Программный:
TextView programmaticallyTextView = (TextView)
findViewById(R.id.programmatically_text_view);
programmaticallyTextView.setTypeface(OpenSans.getInstance(this)
.getTypeFace());
Ответ 4
Старый вопрос, но я, конечно, хочу, чтобы я прочитал этот ответ здесь, прежде чем начал свой собственный поиск хорошего решения. Calligraphy расширяет атрибут android:fontFamily
, чтобы добавить поддержку пользовательских шрифтов в вашу папку с ресурсами, например:
<TextView
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="fonts/Roboto-Bold.ttf"/>
Единственное, что вам нужно сделать, чтобы активировать его, - это привязать его к Контексту используемой вами операции:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(new CalligraphyContextWrapper(newBase));
}
Вы также можете указать свой собственный настраиваемый атрибут для замены android:fontFamily
Он также работает в темах, включая AppTheme.
Ответ 5
Если у вас есть только один шрифт, который вы хотели бы добавить, и вам нужно меньше писать код, вы можете создать выделенный TextView для вашего конкретного шрифта. См. Код ниже.
package com.yourpackage;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class FontTextView extends TextView {
public static Typeface FONT_NAME;
public FontTextView(Context context) {
super(context);
if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
this.setTypeface(FONT_NAME);
}
public FontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
this.setTypeface(FONT_NAME);
}
public FontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
this.setTypeface(FONT_NAME);
}
}
В main.xml теперь вы можете добавить свой текстовый вид следующим образом:
<com.yourpackage.FontTextView
android:id="@+id/tvTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
Ответ 6
Использование DataBinding:
@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"/>
Файл шрифта должен находиться в assets/fonts/
Ответ 7
Лучший способ сделать это. От версии предварительного просмотра Android O этот способ
1.) Щелкните правой кнопкой мыши папку res и выберите " Создать"> "Каталог ресурсов Android". Новый
Появится окно каталога ресурсов.
2.) В списке Тип ресурса выберите шрифт и нажмите кнопку ОК.
3.) Добавьте файлы шрифтов в папку шрифтов. Структура папки ниже генерирует R.font.dancing_script, R.font.la_la и R.font.ba_ba.
4.) Дважды щелкните файл шрифта, чтобы просмотреть шрифты файла в редакторе.
Затем мы должны создать семейство шрифтов
1.) Щелкните правой кнопкой мыши папку шрифта и выберите " Создать"> "Файл ресурсов шрифта". Откроется окно "Новый файл ресурсов".
2.) Введите имя файла и нажмите кнопку "ОК". Новый редактор шрифтов XML открывается в редакторе.
3.) Включите каждый атрибут файла шрифта, стиля и веса в элементе тега шрифта. Следующий XML иллюстрирует добавление атрибутов, связанных шрифтом, в XML-ресурс шрифта:
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
<font
android:fontStyle="normal"
android:fontWeight="400"
android:font="@font/hey_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="@font/hey_bababa" />
</font-family>
Добавление шрифтов в TextView:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
**android:fontFamily="@font/ba_ba"**/>
Как из документации
Работа со шрифтами
все шаги верны.
Ответ 8
Расширьте TextView
и присвойте ему настраиваемый атрибут или просто используйте атрибут android: tag для передачи в строке того шрифта, который вы хотите использовать. Вам нужно будет выбрать соглашение и придерживаться его, например, я поместил все мои шрифты в папку res/assets/fonts/, чтобы ваш класс TextView знал, где их найти. Затем в вашем конструкторе вы просто устанавливаете шрифт вручную после супервызов.
Ответ 9
Единственный способ использования пользовательских шрифтов - через исходный код.
Просто помните, что Android работает на устройствах с очень ограниченными ресурсами, а шрифты могут потребовать достаточного объема оперативной памяти. Встроенные Droid шрифты специально сделаны, и, если вы заметили, у вас осталось много символов и украшений.
Ответ 10
У меня может быть простой ответ на вопрос без расширения TextView и реализации длинного кода.
Код:
TextView tv = (TextView) findViewById(R.id.textview1);
tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));
Поместите произвольный файл шрифта в папку с ресурсами, как обычно, и попробуйте это. Меня устраивает.
Я просто не понимаю, почему peter дал такой огромный код для этой простой вещи, или он дал свой ответ в старой версии.
Ответ 11
Также может быть определено в xml без создания пользовательских классов
style.xml
<style name="ionicons" parent="android:TextAppearance">
<!-- Custom Attr-->
<item name="fontPath">fonts/ionicons.ttf</item>
</style>
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/ionicons"
android:text=""/>
</LinearLayout>
Быстрое замечание, потому что я всегда забывал, куда помещать шрифты, его шрифт должен быть внутри assets
, и эта папка находится на том же уровне, что res
и src
, в моем случае его assets/fonts/ionicons.ttf
Обновлен Добавлен корневой макет, потому что для этого метода требуется xmlns:app="http://schemas.android.com/apk/res-auto"
Обновление 2 Забыл о библиотеке, которую я установил, перед вызовом Calligraphy
Ответ 12
Ответ Peter лучший, но его можно улучшить, используя styles.xml от Android, чтобы настроить шрифты для всех текстовых просмотров в вашем приложении.
Мой код здесь
Ответ 13
Существует два способа настройки шрифтов:
!!! мой пользовательский шрифт в активах /fonts/iran _sans.ttf
Способ 1:
Refrection Typeface.class ||| лучший способ
вызов FontsOverride.setDefaultFont() в классе extends Application, этот код приведет к изменению всех шрифтов программного обеспечения, даже шрифтов Toasts
AppController.java
public class AppController extends Application {
@Override
public void onCreate() {
super.onCreate();
//Initial Font
FontsOverride.setDefaultFont(getApplicationContext(), "MONOSPACE", "fonts/iran_sans.ttf");
}
}
FontsOverride.java
public class FontsOverride {
public static void setDefaultFont(Context context, String staticTypefaceFieldName, String fontAssetName) {
final Typeface regular = Typeface.createFromAsset(context.getAssets(), fontAssetName);
replaceFont(staticTypefaceFieldName, regular);
}
private static void replaceFont(String staticTypefaceFieldName, final Typeface newTypeface) {
try {
final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName);
staticField.setAccessible(true);
staticField.set(null, newTypeface);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Способ 2: использовать setTypeface
для специального вида просто вызовите setTypeface(), чтобы изменить шрифт.
CTextView.java
public class CTextView extends TextView {
public CTextView(Context context) {
super(context);
init(context,null);
}
public CTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context,attrs);
}
public void init(Context context, @Nullable AttributeSet attrs) {
if (isInEditMode())
return;
// use setTypeface for change font this view
setTypeface(FontUtils.getTypeface("fonts/iran_sans.ttf"));
}
}
FontUtils.java
public class FontUtils {
private static Hashtable<String, Typeface> fontCache = new Hashtable<>();
public static Typeface getTypeface(String fontName) {
Typeface tf = fontCache.get(fontName);
if (tf == null) {
try {
tf = Typeface.createFromAsset(AppController.getInstance().getApplicationContext().getAssets(), fontName);
} catch (Exception e) {
e.printStackTrace();
return null;
}
fontCache.put(fontName, tf);
}
return tf;
}
}
Ответ 14
Вот учебник, в котором показано, как настроить пользовательский шрифт, например @peter: http://responsiveandroid.com/2012/03/15/custom-fonts-in-android-widgets.html
он также учитывает потенциальные утечки памяти ala http://code.google.com/p/android/issues/detail?id=9904. Также в учебнике приведен пример настройки пользовательского шрифта на кнопке.
Ответ 15
Вы можете легко настраивать класс текстового вида: -
Итак, что вам нужно сделать, сделайте Custom textview
класс, который расширен с AppCompatTextView
.
public class CustomTextView extends AppCompatTextView {
private int mFont = FontUtils.FONTS_NORMAL;
boolean fontApplied;
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, context);
}
public CustomTextView(Context context) {
super(context);
init(null, context);
}
protected void init(AttributeSet attrs, Context cxt) {
if (!fontApplied) {
if (attrs != null) {
mFont = attrs.getAttributeIntValue(
"http://schemas.android.com/apk/res-auto", "Lato-Regular.ttf",
-1);
}
Typeface typeface = getTypeface();
int typefaceStyle = Typeface.NORMAL;
if (typeface != null) {
typefaceStyle = typeface.getStyle();
}
if (mFont > FontUtils.FONTS) {
typefaceStyle = mFont;
}
FontUtils.applyFont(this, typefaceStyle);
fontApplied = true;
}
}
}
Теперь, каждый раз, когда пользовательский вызов текстового вида вызывается, и мы получим значение int из атрибута int fontValue = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto","Lato-Regular.ttf",-1)
.
Или же
Мы также можем получить getTypeface() из представления, которое мы установили в нашем xml (android:textStyle="bold|normal|italic"
). Так делайте то, что вы хотите делать.
Теперь мы создаем FontUtils
для установки любого шрифта FontUtils
на наш взгляд.
public class FontUtils {
public static final int FONTS = 1;
public static final int FONTS_NORMAL = 2;
public static final int FONTS_BOLD = 3;
public static final int FONTS_BOLD1 = 4;
private static Map<String, Typeface> TYPEFACE = new HashMap<String, Typeface>();
static Typeface getFonts(Context context, String name) {
Typeface typeface = TYPEFACE.get(name);
if (typeface == null) {
typeface = Typeface.createFromAsset(context.getAssets(), name);
TYPEFACE.put(name, typeface);
}
return typeface;
}
public static void applyFont(TextView tv, int typefaceStyle) {
Context cxt = tv.getContext();
Typeface typeface;
if(typefaceStyle == Typeface.BOLD_ITALIC) {
typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
}else if (typefaceStyle == Typeface.BOLD || typefaceStyle == SD_FONTS_BOLD|| typefaceStyle == FONTS_BOLD1) {
typeface = FontUtils.getFonts(cxt, "FaktPro-SemiBold.ttf");
} else if (typefaceStyle == Typeface.ITALIC) {
typeface = FontUtils.getFonts(cxt, "FaktPro-Thin.ttf");
} else {
typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
}
if (typeface != null) {
tv.setTypeface(typeface);
}
}
}
Ответ 16
Fontinator - это Android-библиотека, облегчающая использование пользовательских шрифтов.
https://github.com/svendvd/Fontinator
Ответ 17
Вы не можете расширить TextView для создания виджета или использовать его в макете виджетов:
http://developer.android.com/guide/topics/appwidgets/index.html