2010-03-04 114 views
168

我想在Android中使用XML文件来定义GUI布局。据我所知,无法指定您的小部件应该使用XML文件中的自定义字体(例如,您放置在assets/font /中的字体),并且只能使用系统安装的字体。自定义字体和XML布局(Android)

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

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

+66

DrDefrost - 请接受一些答案,您将在本网站上获得更多回复。 – SK9 2011-09-03 01:52:18

+1

另外还有一个类似的问题:http://stackoverflow.com/questions/9030204/how-to-use-custom-font-in-android-xml – Vins 2013-05-16 13:12:10

+0

更新05/2017:“支持库26.0测试版提供支助运行Android API版本14和更高版本的设备上的XML字体。“请参阅:https://developer.android.com/preview/features/fonts-in-xml.html#using-support-lib – 2017-05-23 14:12:06

回答

4

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

请记住,Android运行在资源非常有限且字体可能需要大量内存的设备上。内置的Droid字体是专门制作的,如果您注意,缺少许多字符和装饰。

+0

“只要记住的Android设备上运行的资源非常有限” - >这是越来越少而不是这种情况。四核手机?真?? – Sandy 2012-08-10 03:33:10

+9

我会更多地考虑tareqHs答案的背景,这在你的评论中早于2年半。 – SK9 2012-12-18 12:45:13

+0

当你在2010年编写答案时,你的回应的第一部分可能是真实的。后者是超能力的,并且在这一点上:Droid很糟糕,在2012年被Google弃用而转向Roboto。 Android中缺少印刷术的选择是一个缺陷,而不是一个特征;按照今天的标准,iOS自2008年以来已经在原始设备下为开发者提供了多种字体。 – cosmix 2013-10-03 14:50:19

5

延伸TextView并给它一个自定义属性,或者只是使用android:tag属性传递一个你想要使用什么字体的字符串。您需要选择一个约定并坚持下去,例如我将所有字体都放在res/assets/fonts /文件夹中,以便您的TextView类知道在哪里找到它们。然后在你的构造函数中,你只需在超级调用之后手动设置字体。

+1

查看peter的答案,获取完整代码示例。 – Intrications 2011-08-26 10:57:49

217

可以扩展TextView中设置自定义字体作为我学到here

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 /值)

<?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”放入资产文件夹中。

UPDATE 13年8月1日

有严重的内存关切此方法。请参阅下面的chedabob's comment

+0

非常好。感谢代码。 – Intrications 2011-08-26 10:56:37

+5

这看起来不错,但是,当我尝试在main.xml中使用“TextViewPlus”时出现错误。我得到如下: - 错误:错误解析XML:绑定前缀 - 前缀“富”的属性为“foo:CustomFont的”与元素类型“supportLibs.TextViewPlus”相关的不 \t界。 – Majjoodi 2011-11-17 15:11:33

+76

有一点需要注意的是,这将产生几十个和几十个TypeFace对象并吃掉内存。 4.0之前版本的Android中存在一个缺陷,无法正确释放TypeFaces。最简单的做法是用HashMap创建一个TypeFace缓存。这使我的应用程序的内存使用量从120+ mb降至18mb。 http://code.google.com/p/android/issues/detail?id=9904 – chedabob 2012-01-24 14:20:29

7

如果您只想添加一种字体,并且想要编写较少的代码,则可以为您的特定字体创建专用的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="" /> 
+0

在init()上执行此操作并保存3x的同一个调用。 – ericosg 2013-12-07 10:07:51

+0

@ericosg我得到这个错误,当我使用yourthis解决方案 android.view.InflateException:二进制XML文件行#9:错误充气类com.ascent.adwad.utils.CustomTextView – 2014-12-30 12:53:26

+0

@SagarDevanga,很难帮助没有更多的信息。也许尽可能地采取它,并提出一个新的问题。 – ericosg 2014-12-31 09:09:07

1

彼得的回答是最好的,但它可以通过使用styles.xml从Android的定制可以提高你的适用于您应用中所有文字视图的字体。

我的代码是here

18

这可能是晚了一点,但你需要创建一个返回自定义字体,以避免内存泄漏一个单独的类。

字体类:

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

似乎在运行时工作,但它应该在设计器中工作? – 2013-05-05 13:50:32

+0

当然。你可以使用xml。 @Magnus – 2013-05-05 22:32:49

+0

我想你误解了,它似乎并没有在_Design_时间(设计器预览)中工作。 (xml!=设计师)。它在编译到运行时的Xml布局文件中指定工作正常。无论如何,我使用这个扩展https://github.com/danh32/Fontify,它对我的​​需求更好(它支持多种字体样式,常规,粗体等,以及不同的字体名称以及其他控件超越TextView) – 2013-05-06 11:25:39

35

我对派对迟了3年:(但这可能会对可能会偶然发现此帖的人有用。

我已经写了一个缓存字体的库,并允许您从XML中指定自定义字体。你可以找到图书馆here

这是您的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" /> 
+0

非常感谢你,你摇滚! – Udo 2014-05-13 10:18:03

+0

@UD创建你不客气。 – 2014-05-20 07:36:54

+0

嘿@ Ragunath-jawahar,我将如何导入一个Gradle项目的图书馆?我试过'编译'com.mobsandgeeks:android-typeface-textview:1.0''但是没有奏效。 – aimango 2014-06-14 23:21:57

2

我可能没有扩展TextView和实现一个长代码的问题有一个简单的答案。

代码:

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

将资产文件夹像往常一样自定义字体文件,试试这个。这个对我有用。 我只是不明白为什么彼得为这个简单的事情给了这么大的代码,或者他在旧版本中给出了他的答案。

13

老问题,但我确实希望我在这里阅读这个答案之前,我开始自己的搜索一个很好的解决方案。 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。

7

使用数据绑定

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

+3

我会在那里放置代码? – 707 2016-03-28 09:57:36

2

还可以在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这个文件夹所在在同级别ressrc,在我的情况下,它assets/fonts/ionicons.ttf

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

更新2忘了,我已经安装之前调用Calligraphy

+0

这对我不起作用。当我尝试构建这个时,我得到错误消息:错误:(49,5)未找到与给定名称匹配的资源:attr'fontPath'。 – Stef 2015-11-04 16:33:11

+0

尝试添加'xmlns:app =“http://schemas.android。com/apk/res-auto“'到你的根布局,检查更新的答案也 – norman784 2015-11-05 03:26:44

+0

错误不是来自布局XML文件,而是来自样式XML文件。它似乎并不知道什么是一个fontPath 。 – Stef 2015-11-05 09:25:51

5

做到这一点从Android的Ø预览版的最佳方法库是这样
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"**/> 

由于从文档

Working With Fonts

所有步骤都正确。

2

有两种自定义字体的方法:

!!!我的自定义字体资产/字体/ iran_sans.ttf

方式1: Refrection Typeface.class ||| 最好的办法

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

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

} 
0

您可以轻松地自定义的TextView类: -

所以,你首先需要做什么,使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 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); 
     } 
    } 
}