[英]Is it possible to set a custom font for entire of application?
我需要為我的整個應用程序使用某些字體。 我有相同的.ttf文件。 是否可以在應用程序啟動時將其設置為默認字體,然后在應用程序的其他位置使用它? 設置后,如何在布局XML中使用它?
是的反思。 這是有效的( 根據這個答案 ):
(注意:由於缺乏對自定義字體的支持,這是一種解決方法,所以如果你想改變這種情況,請在這里做明星向上投票安卓問題 )。 注意:不要在這個問題上留下“我也是”的評論,每個看過它的人都會收到一封電子郵件。 所以請“明星”吧。
import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;
public final class FontsOverride {
public static void setDefaultFont(Context context,
String staticTypefaceFieldName, String fontAssetName) {
final Typeface regular = Typeface.createFromAsset(context.getAssets(),
fontAssetName);
replaceFont(staticTypefaceFieldName, regular);
}
protected 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();
}
}
}
然后,您需要重載幾個默認字體,例如在應用程序類中:
public final class Application extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
}
}
或者當然如果你使用相同的字體文件,你可以改進它只加載一次。
但是我傾向於覆蓋一個,說"MONOSPACE"
,然后設置一個樣式來強制該字體字體應用程序:
<resources>
<style name="AppBaseTheme" parent="android:Theme.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:typeface">monospace</item>
</style>
</resources>
我已經在評論中調查了它不起作用的報告,它似乎與主題android:Theme.Material.Light
不兼容。
如果該主題對您不重要,請使用較舊的主題,例如:
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:typeface">monospace</item>
</style>
在android中有一個很棒的自定義字體庫: 書法
這是一個如何使用它的示例。
在Gradle中,您需要將此行放入應用程序的build.gradle文件中:
dependencies {
compile 'uk.co.chrisjenx:calligraphy:2.2.0'
}
然后創建一個擴展Application
的類並編寫此代碼:
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
.setDefaultFontPath("your font path")
.setFontAttrId(R.attr.fontPath)
.build()
);
}
}
並且在activity類中將此方法放在onCreate之前:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
你的清單文件應該是這樣的最后一件事:
<application
.
.
.
android:name=".App">
它會將整個活動改為你的字體! 它簡單而干凈!
雖然這不適用於整個應用程序,但它適用於活動,可以重復用於任何其他活動。 我已經更新了我的代碼,感謝@ FR073N以支持其他視圖。 我不確定Buttons
, RadioGroups
等的問題,因為這些類都擴展TextView
所以它們應該可以正常工作。 我為使用反射添加了一個布爾條件,因為它似乎非常hackish並且可能會顯着地影響性能。
注意:正如所指出的,這不適用於動態內容! 為此,可以使用onCreateView
或getView
方法調用此方法,但需要額外的工作。
/**
* Recursively sets a {@link Typeface} to all
* {@link TextView}s in a {@link ViewGroup}.
*/
public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{
if (mContainer == null || mFont == null) return;
final int mCount = mContainer.getChildCount();
// Loop through all of the children.
for (int i = 0; i < mCount; ++i)
{
final View mChild = mContainer.getChildAt(i);
if (mChild instanceof TextView)
{
// Set the font if it is a TextView.
((TextView) mChild).setTypeface(mFont);
}
else if (mChild instanceof ViewGroup)
{
// Recursively attempt another ViewGroup.
setAppFont((ViewGroup) mChild, mFont);
}
else if (reflect)
{
try {
Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
mSetTypeface.invoke(mChild, mFont);
} catch (Exception e) { /* Do something... */ }
}
}
}
然后使用它你會做這樣的事情:
final Typeface mFont = Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf");
final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, mFont);
希望有所幫助。
綜上所述:
選項#1:使用反射來應用字體(結合weston和Roger Huang的答案):
import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.Typeface;
public final class FontsOverride {
public static void setDefaultFont(Context context,
String staticTypefaceFieldName, String fontAssetName) {
final Typeface regular = Typeface.createFromAsset(context.getAssets(),
fontAssetName);
replaceFont(staticTypefaceFieldName, regular);
}
protected static void replaceFont(String staticTypefaceFieldName,final Typeface newTypeface) {
if (isVersionGreaterOrEqualToLollipop()) {
Map<String, Typeface> newMap = new HashMap<String, Typeface>();
newMap.put("sans-serif", newTypeface);
try {
final Field staticField = Typeface.class.getDeclaredField("sSystemFontMap");
staticField.setAccessible(true);
staticField.set(null, newMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
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();
}
}
}
}
Application類中的用法:
public final class Application extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
FontsOverride.setDefaultFont(this, "DEFAULT", "MyFontAsset.ttf");
FontsOverride.setDefaultFont(this, "MONOSPACE", "MyFontAsset2.ttf");
FontsOverride.setDefaultFont(this, "SERIF", "MyFontAsset3.ttf");
FontsOverride.setDefaultFont(this, "SANS_SERIF", "MyFontAsset4.ttf");
}
}
設置一個樣式來強制該字體字體應用程序(基於lovefish ):
預棒棒糖:
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:typeface">monospace</item>
</style>
</resources>
棒棒糖(API 21):
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:textAppearance">@style/CustomTextAppearance</item>
</style>
<style name="CustomTextAppearance">
<item name="android:typeface">monospace</item>
</style>
</resources>
選項2:將每個視圖子類化為您需要自定義字體的位置,即。 ListView,EditTextView,Button等( Palani的回答):
public class CustomFontView extends TextView {
public CustomFontView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomFontView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomFontView(Context context) {
super(context);
init();
}
private void init() {
if (!isInEditMode()) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
setTypeface(tf);
}
}
選項3:實現遍歷當前屏幕視圖層次結構的View Crawler:
變化#1( 湯姆的回答):
public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect)
{
if (mContainer == null || mFont == null) return;
final int mCount = mContainer.getChildCount();
// Loop through all of the children.
for (int i = 0; i < mCount; ++i)
{
final View mChild = mContainer.getChildAt(i);
if (mChild instanceof TextView)
{
// Set the font if it is a TextView.
((TextView) mChild).setTypeface(mFont);
}
else if (mChild instanceof ViewGroup)
{
// Recursively attempt another ViewGroup.
setAppFont((ViewGroup) mChild, mFont);
}
else if (reflect)
{
try {
Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
mSetTypeface.invoke(mChild, mFont);
} catch (Exception e) { /* Do something... */ }
}
}
}
用法:
final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
HomeActivity.setAppFont(mContainer, Typeface.createFromAsset(getAssets(),
"fonts/MyFont.ttf"));
變體#2: https : //coderwall.com/p/qxxmaa/android-use-a-custom-font-everywhere 。
選項#4:使用名為Calligraphy的第三方Lib。
就個人而言,我會推薦選項#4,因為它可以節省很多麻煩。
我想改進weston對API 21 Android 5.0的回答。
在API 21下,大多數文本樣式都包含fontFamily設置,如:
<style name="TextAppearance.Material">
<item name="fontFamily">@string/font_family_body_1_material</item>
</style>
哪個適用默認的Roboto Regular字體:
<string name="font_family_body_1_material">sans-serif</string>
原始答案無法應用等寬字體,因為android:fontFamily對android:typeface屬性( 引用 )具有更高的優先級。 使用Theme.Holo。*是一個有效的解決方法,因為里面沒有android:fontFamily設置。
由於Android 5.0將系統字體放在靜態變量Typeface.sSystemFontMap( 引用 )中,我們可以使用相同的反射技術來替換它:
protected static void replaceFont(String staticTypefaceFieldName,
final Typeface newTypeface) {
if (isVersionGreaterOrEqualToLollipop()) {
Map<String, Typeface> newMap = new HashMap<String, Typeface>();
newMap.put("sans-serif", newTypeface);
try {
final Field staticField = Typeface.class
.getDeclaredField("sSystemFontMap");
staticField.setAccessible(true);
staticField.set(null, newMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
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();
}
}
}
它非常簡單...... 1.下載並將自定義字體放入資產中..然后為文本視圖編寫一個單獨的類,如下所示:這里我使用了futura字體
public class CusFntTextView extends TextView {
public CusFntTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CusFntTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CusFntTextView(Context context) {
super(context);
init();
}
private void init() {
if (!isInEditMode()) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "Futura.ttf");
setTypeface(tf);
}
}
}
並在xml中執行以下操作:
<com.packagename.CusFntTextView
android:id="@+id/tvtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi Android"
android:textAppearance="?android:attr/textAppearanceLarge"
/>
我還建議擴展TextView和其他控件,但我認為在構造中設置字體會更好。
public FontTextView(Context context) {
super(context);
init();
}
public FontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
protected void init() {
setTypeface(Typeface.createFromAsset(getContext().getAssets(), AppConst.FONT));
}
我希望通過主題為“ Theme.AppCompat ”的API 21 Android棒棒糖來改進weston和Roger Huang的答案。
Android 4.4以下
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:typeface">monospace</item>
</style>
</resources>
超過(相等)API 5.0
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:textAppearance">@style/CustomTextAppearance</item>
</style>
<style name="CustomTextAppearance">
<item name="android:typeface">monospace</item>
</style>
</resources>
而FontsOverride util的文件是一樣的東西在韋斯頓的答案。 我在這些手機上測試過:
Nexus 5(android 5.1主Android系統)
中興V5(android 5.1 CM12.1)
XIAOMI note(android 4.4 MIUI6)
HUAWEI C8850(android 2.3.5 UNKNOWN)
可以在這里找到一個出色的解決方案: https : //coderwall.com/p/qxxmaa/android-use-a-custom-font-everywhere 。
只需從BaseActivity擴展活動並編寫這些方法。 此外,您應該更好地緩存字體,如下所述: https : //stackoverflow.com/a/16902532/2914140 。
經過一些研究,我編寫了適用於三星Galaxy Tab A(Android 5.0)的代碼。 使用的代碼為weston和Roger Huang以及https://stackoverflow.com/a/33236102/2914140 。 也在聯想TAB 2 A10-70L上進行了測試,它不起作用。 我在這里插入了一個字體'Comic Sans'以便看到差異。
import android.content.Context;
import android.graphics.Typeface;
import android.os.Build;
import android.util.Log;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class FontsOverride {
private static final int BOLD = 1;
private static final int BOLD_ITALIC = 2;
private static final int ITALIC = 3;
private static final int LIGHT = 4;
private static final int CONDENSED = 5;
private static final int THIN = 6;
private static final int MEDIUM = 7;
private static final int REGULAR = 8;
private Context context;
public FontsOverride(Context context) {
this.context = context;
}
public void loadFonts() {
Map<String, Typeface> fontsMap = new HashMap<>();
fontsMap.put("sans-serif", getTypeface("comic.ttf", REGULAR));
fontsMap.put("sans-serif-bold", getTypeface("comic.ttf", BOLD));
fontsMap.put("sans-serif-italic", getTypeface("comic.ttf", ITALIC));
fontsMap.put("sans-serif-light", getTypeface("comic.ttf", LIGHT));
fontsMap.put("sans-serif-condensed", getTypeface("comic.ttf", CONDENSED));
fontsMap.put("sans-serif-thin", getTypeface("comic.ttf", THIN));
fontsMap.put("sans-serif-medium", getTypeface("comic.ttf", MEDIUM));
overrideFonts(fontsMap);
}
private void overrideFonts(Map<String, Typeface> typefaces) {
if (Build.VERSION.SDK_INT == 21) {
try {
final Field field = Typeface.class.getDeclaredField("sSystemFontMap");
field.setAccessible(true);
Map<String, Typeface> oldFonts = (Map<String, Typeface>) field.get(null);
if (oldFonts != null) {
oldFonts.putAll(typefaces);
} else {
oldFonts = typefaces;
}
field.set(null, oldFonts);
field.setAccessible(false);
} catch (Exception e) {
Log.e("TypefaceUtil", "Cannot set custom fonts");
}
} else {
try {
for (Map.Entry<String, Typeface> entry : typefaces.entrySet()) {
final Field staticField = Typeface.class.getDeclaredField(entry.getKey());
staticField.setAccessible(true);
staticField.set(null, entry.getValue());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
private Typeface getTypeface(String fontFileName, int fontType) {
final Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/" + fontFileName);
return Typeface.create(tf, fontType);
}
}
要在整個應用程序中運行代碼,您應該在類似Application的類中編寫以下內容:
new FontsOverride(this).loadFonts();
在'assets'中創建一個'fonts'文件夾,並在那里放置所需的字體。 可以在此處找到一條簡單的說明: https : //stackoverflow.com/a/31697103/2914140 。
Lenovo設備也錯誤地獲取字體值。 在大多數情況下,它返回Typeface.NORMAL,有時為null。 即使TextView是粗體(在xml文件布局中)。 請參見此處: TextView isBold始終返回NORMAL 。 這樣,屏幕上的文本始終采用自然字體,而不是粗體或斜體。 所以我認為這是制作人的錯誤。
為Xamarin.Android工作:
類:
public class FontsOverride
{
public static void SetDefaultFont(Context context, string staticTypefaceFieldName, string fontAssetName)
{
Typeface regular = Typeface.CreateFromAsset(context.Assets, fontAssetName);
ReplaceFont(staticTypefaceFieldName, regular);
}
protected static void ReplaceFont(string staticTypefaceFieldName, Typeface newTypeface)
{
try
{
Field staticField = ((Java.Lang.Object)(newTypeface)).Class.GetDeclaredField(staticTypefaceFieldName);
staticField.Accessible = true;
staticField.Set(null, newTypeface);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
應用實施:
namespace SomeAndroidApplication
{
[Application]
public class App : Application
{
public App()
{
}
public App(IntPtr handle, JniHandleOwnership transfer)
: base(handle, transfer)
{
}
public override void OnCreate()
{
base.OnCreate();
FontsOverride.SetDefaultFont(this, "MONOSPACE", "fonts/Roboto-Light.ttf");
}
}
}
樣式:
<style name="Theme.Storehouse" parent="Theme.Sherlock">
<item name="android:typeface">monospace</item>
</style>
從Android O開始,現在可以直接從XML定義, 我的bug現已關閉!
TL; DR:
首先,您必須將字體添加到項目中
其次你添加一個字體系列,如下所示:
<?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/lobster_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="@font/lobster_italic" />
</font-family>
最后,您可以在布局或樣式中使用該字體:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/lobster"/>
<style name="customfontstyle" parent="@android:style/TextAppearance.Small">
<item name="android:fontFamily">@font/lobster</item>
</style>
請享用!
您可以逐個為每個布局設置自定義字體,只需通過傳遞其根View來從每個布局調用一個函數。首先,創建一個singelton方法來訪問這樣的字體對象
public class Font {
private static Font font;
public Typeface ROBO_LIGHT;
private Font() {
}
public static Font getInstance(Context context) {
if (font == null) {
font = new Font();
font.init(context);
}
return font;
}
public void init(Context context) {
ROBO_LIGHT = Typeface.createFromAsset(context.getAssets(),
"Roboto-Light.ttf");
}
}
您可以在上面的類中定義不同的字體,現在定義一個將應用字體的字體Helper類:
public class FontHelper {
private static Font font;
public static void applyFont(View parentView, Context context) {
font = Font.getInstance(context);
apply((ViewGroup)parentView);
}
private static void apply(ViewGroup parentView) {
for (int i = 0; i < parentView.getChildCount(); i++) {
View view = parentView.getChildAt(i);
//You can add any view element here on which you want to apply font
if (view instanceof EditText) {
((EditText) view).setTypeface(font.ROBO_LIGHT);
}
if (view instanceof TextView) {
((TextView) view).setTypeface(font.ROBO_LIGHT);
}
else if (view instanceof ViewGroup
&& ((ViewGroup) view).getChildCount() > 0) {
apply((ViewGroup) view);
}
}
}
}
在上面的代碼中,我只在textView和EditText上應用字體,你也可以在其他視圖元素上同樣應用字體。你只需要將根視圖組的id傳遞給上面的apply font方法。 例如你的布局是:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/mainParent"
tools:context="${relativePackage}.${activityClass}" >
<RelativeLayout
android:id="@+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/homeFooter"
android:layout_below="@+id/edit" >
<ImageView
android:id="@+id/PreviewImg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/abc_list_longpressed_holo"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/visibilityLayer"
android:layout_width="match_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/UseCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:src="@drawable/camera" />
<TextView
android:id="@+id/tvOR"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/UseCamera"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="OR"
android:textSize="30dp" />
<TextView
android:id="@+id/tvAND"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="OR"
android:textSize="30dp" />
</RelativeLayout>
在Above Layout中,根父ID是“Main Parent”,現在讓我們應用字體
public class MainActivity extends BaseFragmentActivity {
private EditText etName;
private EditText etPassword;
private TextView tvTitle;
public static boolean isHome = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Font font=Font.getInstance(getApplicationContext());
FontHelper.applyFont(findViewById(R.id.mainParent), getApplicationContext());
}
}
干杯:)
我建議擴展TextView,並始終在XML布局中或任何需要TextView的地方使用自定義TextView。 在自定義TextView中,覆蓋setTypeface
@Override
public void setTypeface(Typeface tf, int style) {
//to handle bold, you could also handle italic or other styles here as well
if (style == 1){
tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans700.otf");
}else{
tf = Typeface.createFromAsset(getContext().getApplicationContext().getAssets(), "MuseoSans500.otf");
}
super.setTypeface(tf, 0);
}
Tom的解決方案效果很好,但只適用於TextView和EditText。
如果你想覆蓋大部分視圖(RadioGroup,TextView,Checkbox ......),我創建了一個方法:
protected void changeChildrenFont(ViewGroup v, Typeface font){
for(int i = 0; i < v.getChildCount(); i++){
// For the ViewGroup, we'll have to use recursivity
if(v.getChildAt(i) instanceof ViewGroup){
changeChildrenFont((ViewGroup) v.getChildAt(i), font);
}
else{
try {
Object[] nullArgs = null;
//Test wether setTypeface and getTypeface methods exists
Method methodTypeFace = v.getChildAt(i).getClass().getMethod("setTypeface", new Class[] {Typeface.class, Integer.TYPE});
//With getTypefaca we'll get back the style (Bold, Italic...) set in XML
Method methodGetTypeFace = v.getChildAt(i).getClass().getMethod("getTypeface", new Class[] {});
Typeface typeFace = ((Typeface)methodGetTypeFace.invoke(v.getChildAt(i), nullArgs));
//Invoke the method and apply the new font with the defined style to the view if the method exists (textview,...)
methodTypeFace.invoke(v.getChildAt(i), new Object[] {font, typeFace == null ? 0 : typeFace.getStyle()});
}
//Will catch the view with no such methods (listview...)
catch (Exception e) {
e.printStackTrace();
}
}
}
}
此方法將返回以XML格式設置的視圖樣式(粗體,斜體......),並在它們存在時應用它們。
對於ListView,我總是創建一個適配器,並在getView中設置字體。
我寫了一個類,為當前視圖層次結構中的視圖分配字體,並基於當前字體屬性(粗體,正常,您可以根據需要添加其他樣式):
public final class TypefaceAssigner {
public final Typeface DEFAULT;
public final Typeface DEFAULT_BOLD;
@Inject
public TypefaceAssigner(AssetManager assetManager) {
DEFAULT = Typeface.createFromAsset(assetManager, "TradeGothicLTCom.ttf");
DEFAULT_BOLD = Typeface.createFromAsset(assetManager, "TradeGothicLTCom-Bd2.ttf");
}
public void assignTypeface(View v) {
if (v instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) v).getChildCount(); i++) {
View view = ((ViewGroup) v).getChildAt(i);
if (view instanceof ViewGroup) {
setTypeface(view);
} else {
setTypeface(view);
}
}
} else {
setTypeface(v);
}
}
private void setTypeface(View view) {
if (view instanceof TextView) {
TextView textView = (TextView) view;
Typeface typeface = textView.getTypeface();
if (typeface != null && typeface.isBold()) {
textView.setTypeface(DEFAULT_BOLD);
} else {
textView.setTypeface(DEFAULT);
}
}
}
}
現在在onViewCreated或onCreateView的所有片段中,onCreate中的所有活動以及getView或newView中的所有視圖適配器中都只調用:
typefaceAssigner.assignTypeface(view);
在帶有build.gradle 3.0.0及更高版本的api 26中,您可以在res中創建一個字體目錄,並在您的樣式中使用此行
<item name="android:fontFamily">@font/your_font</item>
for build build.gradle在build.gradle dependecies中使用它
classpath 'com.android.tools.build:gradle:3.0.0'
最后,谷歌意識到了這個問題的嚴重性(將自定義字體應用於UI組件),他們為它設計了一個干凈的解決方案。
首先,您需要更新以支持庫26+(您可能還需要更新您的gradle {4.0+},android studio),然后您可以創建一個名為font的新資源文件夾。 在此文件夾中,您可以放置字體資源(.tff,...)。 然后你需要覆蓋它們的默認應用程序並強制你的自定義字體:)
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:fontFamily">@font/my_custom_font</item>
</style>
注意:如果您想支持API大於16的設備,則必須使用app namespace而不是android!
我還想改進weston對API 21 Android 5.0的回答。
當我使用DEFAULT字體時,我在三星s5上遇到了同樣的問題。 (與其他字體一起工作正常)
我設法通過在XML文件中為每個Textview或Button設置字體 (例如“sans”)來使其工作
<TextView
android:layout_width="match_parent"
android:layout_height="39dp"
android:textColor="@color/abs__background_holo_light"
android:textSize="12sp"
android:gravity="bottom|center"
android:typeface="sans" />
在MyApplication類中:
public class MyApplication extends Application {
@Override
public void onCreate() {
TypefaceUtil.overrideFont(getApplicationContext(), "SANS_SERIF",
"fonts/my_font.ttf");
}
}
希望能幫助到你。
在某些情況下, 此解決方案無法正常工作。
所以我擴展它:
FontsReplacer.java
public class MyApplication extends Application {
@Override
public void onCreate() {
FontsReplacer.replaceFonts(this);
super.onCreate();
}
}
https://gist.github.com/orwir/6df839e3527647adc2d56bfadfaad805
書法效果很好,但它不適合我,因為它不支持字體系列的不同權重(粗體,斜體等)。
所以我嘗試了Fontain ,它允許您定義自定義視圖並應用它們自定義字體系列。
為了使用Fontain,您應該將以下內容添加到app模塊build.gradle中:
compile 'com.scopely:fontain:1.0.0'
然后,您應該使用FontTextView,而不是使用常規TextView
具有大寫和粗體內容的FontTextView示例:
<com.scopely.fontain.views.FontTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/black"
android:textColor="@android:color/white"
android:textSize="11dp"
android:gravity="center"
android:id="@+id/tv1"
app:font_family="myCustomFont"
app:caps_mode="characters"
app:font_weight="BOLD"/>
package com.theeasylearn.demo.designdemo;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class MyButton extends TextView {
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyButton(Context context) {
super(context);
init();
}
private void init() {
Typeface tf =
Typeface.createFromAsset(
getContext().getAssets(), "angelina.TTF");
setTypeface(tf);
}
}
要更改TextView的默認字體系列,請覆蓋應用主題中的textViewStyle。
要在fontFamily中使用自定義字體,請使用支持庫中的字體資源。
該功能已在Android 26中添加,但通過supportlib向后移植到舊版本。
https://developer.android.com/guide/topics/resources/font-resource.html https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html #使用支持-LIB
自Android Oreo及其支持庫(26.0.0)發布以來,您可以輕松完成此操作。 在另一個問題中參考這個答案 。
基本上你的最終風格將如下所示:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="fontFamily">@font/your_font</item> <!-- target android sdk versions < 26 and > 14 -->
</style>
是的,可以將字體設置為整個應用程序。
完成此操作的最簡單方法是使用您的應用程序打包所需的字體。
要執行此操作,只需在項目根目錄中創建資產/文件夾,並將字體(以TrueType或TTF格式)放入資產中。
例如,您可以創建assets / fonts /並將TTF文件放在那里。
public class FontSampler extends Activity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView tv=(TextView)findViewById(R.id.custom);
Typeface face=Typeface.createFromAsset(getAssets(), "fonts/HandmadeTypewriter.ttf");
tv.setTypeface(face);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.