自定义字体和 XML 布局(Android)

我试图在 Android 中使用 XML 文件定义 GUI 布局。据我所知,没有办法指定你的小部件应该在 XML 文件中使用自定义字体(例如,你已经放置在 asset/font/中的字体) ,而且你只能使用系统安装的字体。

我知道,在 Java 代码中,我可以使用唯一的 ID 手动更改每个小部件的字体。或者,我可以迭代 Java 中的所有小部件来进行这种更改,但是这可能会非常慢。

我还有别的选择吗?有没有更好的方法来制作具有自定义外观的小部件?我并不特别想为每个新添加的小部件手动更改字体。

171092 次浏览

使用自定义字体的唯一方法是通过源代码。

只要记住,Android 运行在资源和字体非常有限的设备上,可能需要大量的 RAM。内置的 Droid 字体是特别制作的,如果你注意到,有许多字符和装饰缺失。

扩展 TextView并给它一个自定义属性,或者仅仅使用 android: tag 属性来传递一个字符串,该字符串包含您想要使用的字体。您需要选择一个约定并坚持它,比如我将把我的所有字体放在 res/asset/fonts/文件夹中,这样您的 TextView 类就知道在哪里可以找到它们。然后在构造函数中,在超级调用之后手动设置字体。

不能扩展 TextView 来创建小部件或在小部件布局中使用小部件: Http://developer.android.com/guide/topics/appwidgets/index.html

您可以扩展 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;
}


}

Xml: (在 res/value 中)

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

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>

您可以将“ saxmon.ttf”放在 资产文件夹中。

更新8/1/13

此方法存在严重的内存问题。请参阅下面的 切达博的评论

下面是一个教程,向您展示如何设置一个像@peter 描述的自定义字体: http://responsiveandroid.com/2012/03/15/custom-fonts-in-android-widgets.html

它还考虑到潜在的内存泄漏。本教程还提供了一个在按钮上设置自定义字体的示例。

如果您只有一种要添加的字体,并且希望编写的代码较少,则可以为特定字体创建专用的 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 中,现在可以像下面这样添加 textView:

<com.yourpackage.FontTextView
android:id="@+id/tvTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />

Peter 的回答是最好的,但是可以通过使用 Android 的 styles.xml 来为应用程序中的所有文本视图定制字体来改进。

我的代码是 给你

这可能有点晚,但是您需要创建一个返回自定义字体的单例类来避免内存泄漏。

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

自定义文本视图:

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());

我已经迟到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" />

对于这个问题,我可能有一个简单的答案,而不需要扩展 TextView 并实现长代码。

密码:

 TextView tv = (TextView) findViewById(R.id.textview1);
tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));

像往常一样将自定义字体文件放入资产文件夹中,然后试试这个。 我只是不明白为什么 Peter 为这个简单的东西给出了如此巨大的代码,或者他用旧版本给出了答案。

这是个老问题了,但是我真希望在我开始寻找一个好的解决方案之前能在这里读到这个答案。书法扩展了 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。

Fontinator 是一个 Android-Library 使得使用自定义字体变得容易。 Https://github.com/svendvd/fontinator

使用 数据绑定:

@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/

也可以在 xml 中定义,而无需创建自定义类

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里面,这个文件夹和 ressrc在同一个级别,在我的情况下是 assets/fonts/ionicons.ttf

更新 增加了根布局,因为这个方法需要 xmlns:app="http://schemas.android.com/apk/res-auto"才能工作

更新2忘记了我之前安装的一个名为“ https://github.com/chrisjenx/Calligography”rel = “ nofollow”> 书法的库

最好的方法来做到这一点从 Android O 预览版就是这种方式
右键单击 文件夹,转到 新建 > Android 资源目录
“资源目录”窗口。
在资源类型列表中,选择 字体,然后单击 OK。
下面的文件夹结构生成 R.font.dance _ script、 R.font.la _ la 和 R.font.ba _ ba。
4) 双击一个字体文件,在编辑器中预览文件的字体。

接下来我们必须创建一个字体系列

右键单击字体文件夹,转到 新增 > 字体资源档案。出现“新建资源文件”窗口。
输入 文件名,然后单击“确定”。新的字体资源 XML 将在编辑器中打开。
3)在 font 标记元素中包含每个字体文件、样式和砝码属性。下面的 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"**/>

从文件上看

使用字体

所有的步骤都是正确的。

自定义字体有两种方法:

! ! ! 我的自定义字体在资产/字体/iran _ sans. ttf

方法一: Refrection Typeface.class | | | < em > 最佳方式

在类中调用 FontsOverride.setDefaultFont ()扩展应用程序,此代码将导致所有软件字体被更改,甚至 Toast 字体

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 ()来更改字体。

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


}

您可以很容易地自定义文本视图类:-

所以你首先需要做的是,使用 AppCompatTextView扩展 Custom textview类。

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 fontValue = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto","Lato-Regular.ttf",-1)获得 int 值。

或者

我们还可以从 xml (android:textStyle="bold|normal|italic")中设置的视图中获取 getTypeface ()。所以你想干什么就干什么吧。

现在,我们将 FontUtils用于将任何.ttf 字体设置到视图中。

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

如果你知道从 Android 8.0(API 级别26)开始你就可以使用 在 XML 中使用自定义字体,这可能会很有用。

可以通过以下方式将自定义字体应用于整个应用程序。

  1. 将字体放在文件夹 res/font中。

  2. res/values/styles.xml中,在应用程序主题中使用它。 < style name = “ AppTheme”father = “{ whatever you like }”> < item name = “ android: fontFamily”>@font/myfont