簡體   English   中英

自定義字體和XML布局(Android)

[英]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文件夾中。

更新8/1/13

這種方法存在嚴重的記憶問題。 請參閱下面的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而且這個文件夾與ressrc位於同一級別,在我的例子中是它的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中的自定義字體,這可能很有用。

您可以通過以下方式將自定義字體應用於整個應用程序。

  1. 將字體放在res/font文件夾中。

  2. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM