2010-03-04 111 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); 
     } 
    } 
}