我需要使用特定的字体为我的整个应用程序。我有。ttf文件相同。 是否有可能将此设置为默认字体,在应用程序启动,然后在应用程序的其他地方使用它?当设置,我如何使用它在我的布局xml ?
当前回答
一个绝妙的解决方案可以在这里找到: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。
联想设备还错误地获取了字体的值。在大多数情况下,它返回字体。NORMAL,有时为空。即使TextView是粗体(在xml文件布局)。看这里:TextView isBold总是返回正常。这样,屏幕上的文本总是使用常规字体,而不是粗体或斜体。所以我认为这是制作人的错误。
其他回答
是的,还有反思。这是可行的(基于这个答案):
(注意:这是一个变通办法,因为缺乏对自定义字体的支持,所以如果你想改变这种情况,请在这里对android问题进行星号投票)。注意:不要在这个问题上留下“我也是”的评论,当你这样做的时候,每个看过它的人都会收到一封电子邮件。所以请给它打上星号。
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>
发射21 Android 5.0
我已经调查了评论中的报告,它不起作用,它似乎与主题机器人:theme . material . light不兼容。
如果这个主题对你来说不重要,那就用一个旧的主题,例如:
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:typeface">monospace</item>
</style>
Tom的解决方案很好,但只适用于TextView和EditText。
如果你想覆盖大部分的视图(RadioGroup, TextView,复选框…),我创建了一个方法:
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中设置字体。
对于Android O,现在可以直接从XML中定义,我的bug现在已经关闭!
详情请看这里
TL; diana:
首先,必须将字体添加到项目中
其次,添加一个字体系列,如下所示:
<?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>
享受吧!
我写了一个类,将字体分配给当前视图层次结构中的视图,并基于当前字体属性(粗体,正常,如果你想,你可以添加其他样式):
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);
虽然这并不适用于整个应用程序,但它适用于一个活动,并且可以重用于任何其他活动。我已经更新了我的代码,感谢@FR073N,以支持其他视图。我不确定的问题与按钮,RadioGroups等,因为这些类都扩展TextView,所以他们应该工作得很好。我为使用反射添加了一个布尔条件,因为它看起来非常笨拙,可能会显著降低性能。
注意:正如所指出的,这将不适用于动态内容!为此,可以用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);
希望这能有所帮助。
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 碎片中的onCreateOptionsMenu
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?