[英]Custom fonts and XML layouts (Android)
我正在嘗試使用Android中的XML文件定義GUI布局。 據我所知,沒有辦法指定您的小部件應該在XML文件中使用自定義字體(例如,您放置在assets / font /中的字體),並且您只能使用系統安裝的字體。
我知道,在Java代碼中,我可以使用唯一ID手動更改每個窗口小部件的字體。 或者,我可以迭代Java中的所有小部件來進行此更改,但這可能會非常慢。
我還有其他選擇嗎? 有沒有更好的方法來制作具有自定義外觀的小部件? 我不是特別想要為我添加的每個新小部件手動更改字體。
您可以擴展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”放在assets文件夾中。
這種方法存在嚴重的記憶問題。 請參閱下面的chedabob評論 。
我參加晚會已經晚了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" />
這可能有點晚,但您需要創建一個返回自定義字體的單例類,以避免內存泄漏。
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());
老問題,但在我開始自己尋找一個好的解決方案之前,我當然希望我在這里讀到這個答案。 書法擴展了android:fontFamily
屬性,以添加對資產文件夾中自定義字體的支持,如下所示:
<TextView
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="fonts/Roboto-Bold.ttf"/>
要激活它,您唯一需要做的就是將它附加到您正在使用的Activity的Context中:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(new CalligraphyContextWrapper(newBase));
}
您還可以指定自己的自定義屬性來替換android:fontFamily
它也適用於主題,包括AppTheme。
使用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/
如果您只想添加一種字體,並且想要編寫更少的代碼,則可以為特定字體創建專用的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="" />
最好的方法從Android O預覽版就是這樣
1.)右鍵單擊res文件夾,然后轉到新建> Android資源目錄 。 新的
出現資源目錄窗口。
2.)在“資源類型”列表中,選擇“ 字體” ,然后單擊“確定”。
3.) 在字體文件夾中添加字體文件 。下面的文件夾結構生成R.font.dancing_script,R.font.la_la和R.font.ba_ba。
4.) 雙擊字體文件以在編輯器中預覽文件的字體。
接下來我們必須創建一個字體系列
1.)右鍵單擊字體文件夾,然后轉到“ 新建”>“字體資源文件” 。 將出現“新建資源文件”窗口。
2.)輸入文件名,然后單擊“確定” 。 新的字體資源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"**/>
從文檔中可以看出
所有步驟都是正確的。
擴展TextView
並為其提供自定義屬性,或者只使用android:tag屬性傳入要使用的字體的String。 您需要選擇一個約定並堅持下去,例如我將所有字體放在res / assets / fonts /文件夾中,以便TextView類知道在哪里找到它們。 然后在構造函數中,您只需在超級調用后手動設置字體。
使用自定義字體的唯一方法是通過源代碼。
請記住,Android在資源非常有限的設備上運行,字體可能需要大量的RAM。 內置的Droid字體是專門制作的,如果你注意到,會丟失許多字符和裝飾。
如果不擴展TextView並實現長代碼,我可能會對這個問題有一個簡單的答案。
代碼:
TextView tv = (TextView) findViewById(R.id.textview1);
tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));
像往常一樣將自定義字體文件放在assets文件夾中並嘗試此操作。 這個對我有用。 我只是不明白為什么彼得為這個簡單的事情提供了如此龐大的代碼,或者他在舊版本中給出了他的答案。
也可以在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
Peter的答案是最好的,但可以通過使用Android的styles.xml為您的應用中的所有文本視圖自定義字體來改進它。
我的代碼在這里
有兩種方法可以自定義字體:
! 我在assets / fonts / iran_sans.ttf中的自定義字體
方式1: Refrection Typeface.class ||| 最好的辦法
在類中調用FontsOverride.setDefaultFont()擴展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;
}
}
您可以輕松制作自定義textview類: -
所以首先需要做的是使用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值int fontValue = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto","Lato-Regular.ttf",-1)
。
要么
我們也可以從我們在xml中設置的視圖中獲取getTypeface()( android:textStyle="bold|normal|italic"
)。 所以做你想做的事。
現在,我們將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中的自定義字體,這可能很有用。
您可以通過以下方式將自定義字體應用於整個應用程序。
將字體放在res/font
文件夾中。
在res/values/styles.xml
,在應用程序主題中使用它。 <style name="AppTheme" parent="{whatever you like}"> <item name="android:fontFamily">@font/myfont</item> </style>
這是一個教程,向您展示如何設置自定義字體,如@peter描述: http ://responsiveandroid.com/2012/03/15/custom-fonts-in-android-widgets.html
它還考慮了潛在的內存泄漏問題http://code.google.com/p/android/issues/detail?id=9904 。 本教程中還有一個在按鈕上設置自定義字體的示例。
Fontinator是一個Android-Library,可以輕松使用自定義字體。 https://github.com/svendvd/Fontinator
您無法擴展TextView以創建窗口小部件或在窗口小部件布局中使用窗口小部件: http : //developer.android.com/guide/topics/appwidgets/index.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.