如何在 Android 中为整个应用程序设置自定义字体?
How to set custom font for a whole application in Android?
是否可以在 Android 应用程序中设置自定义字体?
我尝试了 here 发布的内容,但我不知道我的 extends Application
class 在哪里...
有什么帮助吗?
编辑:
我尝试了以下方法:
- 添加资产文件夹并在其中插入字体,如下所示:
添加从 Application
扩展的新 class
从我的 AndroidManifest.xml
调用这个新的 class。
我去我的风格加了
MyApp.java:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
FontsOverride.setDefaultFont(this, "DEFAULT", "raleway_regular.ttf");
// This FontsOverride comes from the example I posted above
}
}
AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".MyApp"
android:theme="@style/AppTheme">
....
styles.xml:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:fontFamily">default</item>
</style>
但是我的字体还是没有改变...有什么想法吗?
然后 MyApp
class 被调用。但是对我的字体没有影响...
EDIT2: 我意识到在为我的按钮设置自定义样式后,我的按钮应用了自定义字体。这是我的自定义按钮样式:
<style name="MyButtonStyle" parent="Widget.AppCompat.Button">
<item name="textAllCaps">false</item>
<item name="android:textAllCaps">false</item>
</style>
这是现在的样子:
所以:我的按钮正在应用样式,而不是 TextView
。知道为什么我的自定义字体没有应用于应用程序中的所有项目吗?
您似乎在 styles.xml
中使用 android:fontFamily
而不是 android:typeface
。
尝试更换
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:fontFamily">default</item>
</style>
和
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:typeface">default</item>
</style>
写一个class
public class MyApp extends Application{
// Put the onCreate code as you obtained from the post link you reffered
}
现在接下来的事情是 AndroidManifest.xml 应用程序标签,为您的应用程序命名 class。在本例中是 MyApp
<application
android:name=".MyApp"
...
>
...
</application>
所以每次打开应用程序时,都会调用MyApp class的onCreate方法,并设置字体。
更新
将字体文件放在assets/fonts/your_font_file.ttf
下
将此行放在应用程序的 onCreate 方法下 class(MyApp)
TypefaceUtil.overrideFont(getApplicationContext(), "SERIF", "fonts/your_font_file.ttf");
TypefaceUtil 的源文件
public class TypefaceUtil {
/**
* Using reflection to override default typeface
* NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
*
* @param context to work with assets
* @param defaultFontNameToOverride for example "monospace"
* @param customFontFileNameInAssets file name of the font from assets
*/
public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Map<String, Typeface> newMap = new HashMap<String, Typeface>();
newMap.put("serif", customFontTypeface);
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 defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
defaultFontTypefaceField.setAccessible(true);
defaultFontTypefaceField.set(null, customFontTypeface);
} catch (Exception e) {
Log.e(TypefaceUtil.class.getSimpleName(), "Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
}
}
}
}
现在更新您的 style.xml 文件
在清单文件
中将您的 activity 包含的样式放在下面一行
<item name="android:typeface">serif</item>
希望对您有所帮助
首先,创建一个新的 class 来覆盖您想要自定义的任何视图。 (例如,想要一个带有自定义字体的按钮?扩展 Button
)。例如:
public class CustomButton extends Button {
private final static int ROBOTO = 0;
private final static int ROBOTO_CONDENSED = 1;
public CustomButton(Context context) {
super(context);
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context, attrs); //I'll explain this method later
}
public CustomButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
parseAttributes(context, attrs);
}
}
现在,如果您没有,请在 res/values/attrs.xml
下添加一个 XML 文档,然后添加:
<resources>
<!-- Define the values for the attribute -->
<attr name="typeface" format="enum">
<enum name="roboto" value="0"/>
<enum name="robotoCondensed" value="1"/>
</attr>
<!-- Tell Android that the class "CustomButton" can be styled,
and which attributes it supports -->
<declare-styleable name="CustomButton">
<attr name="typeface"/>
</declare-styleable>
</resources>
好吧,让我们回到前面的 parseAttributes()
方法:
private void parseAttributes(Context context, AttributeSet attrs) {
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomButton);
//The value 0 is a default, but shouldn't ever be used since the attr is an enum
int typeface = values.getInt(R.styleable.CustomButton_typeface, 0);
switch(typeface) {
case ROBOTO: default:
//You can instantiate your typeface anywhere, I would suggest as a
//singleton somewhere to avoid unnecessary copies
setTypeface(roboto);
break;
case ROBOTO_CONDENSED:
setTypeface(robotoCondensed);
break;
}
values.recycle();
}
现在你已经准备好了。您可以为任何东西添加更多属性(您可以为 typefaceStyle 添加另一个属性 -- 粗体、斜体等)但现在让我们看看如何使用它:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.yourpackage.name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.yourpackage.name.CustomButton
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me!"
custom:typeface="roboto" />
</LinearLayout>
xmlns:custom
行实际上可以是任何内容,但惯例如上所示。重要的是它是唯一的,这就是使用包名称的原因。现在您只需为属性使用 custom:
前缀,为 android 属性使用 android:
前缀。
最后一件事:如果你想在样式中使用它 (res/values/styles.xml
),你应该 而不是 添加 xmlns:custom
行。仅引用不带前缀的属性名称:
<style name="MyStyle>
<item name="typeface">roboto</item>
</style>
如果您遵循第一个主题,这应该有效:Here
是的,有反思。这有效(based on this answer):
(注意:由于不支持自定义字体,这是一种解决方法,所以如果您想改变这种情况,请在此处为 up-vote 和 android 问题加注星标)。注意:不要在那个问题上留下 "me too" 评论,当你这样做时,所有看过它的人都会收到一封电子邮件。所以请"star"。
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();
}
}
}
然后您需要重载一些默认字体,例如在应用程序中 class:
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>
API 21 Android 5.0
我调查了评论中的报告,说它不起作用,而且似乎与主题不兼容 android:Theme。Material.Light。
如果该主题对您不重要,请使用较旧的主题,例如:
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:typeface">monospace</item>
</style>
编辑
uk.co.chrisjenx:calligraphy
不再为最新 android 版本维护更多的替代版本
https://github.com/InflationX/Calligraphy
dependencies {
implementation 'io.github.inflationx:calligraphy3:3.1.1'
implementation 'io.github.inflationx:viewpump:2.0.3'
}
将您的自定义字体添加到资产/
用法
默认字体
在您的应用程序 class 中的 #onCreate() 方法中使用 CalligraphyConfig 定义您的默认字体,并将其传递给您添加到 ViewPump 构建器的 CalligraphyInterceptor。
@Override
public void onCreate() {
super.onCreate();
ViewPump.init(ViewPump.builder()
.addInterceptor(new CalligraphyInterceptor(
new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/Roboto-RobotoRegular.ttf")
.setFontAttrId(R.attr.fontPath)
.build()))
.build());
//....
}
注入上下文:包装 Activity 上下文:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
}
自定义样式
<style name="TextViewCustomFont">
<item name="fontPath">fonts/RobotoCondensed-Regular.ttf</item>
</style>
对于主题
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:textViewStyle">@style/AppTheme.Widget.TextView</item>
</style>
<style name="AppTheme.Widget"/>
<style name="AppTheme.Widget.TextView" parent="android:Widget.Holo.Light.TextView">
<item name="fontPath">fonts/Roboto-ThinItalic.ttf</item>
</style>
解决方案下方的开发人员不再维护
android:Calligraphy
中有一个很棒的自定义字体库
这是一个如何使用它的示例。
在 Gradle 中,您需要将此行放入应用程序的 build.gradle 文件中:
dependencies {
compile 'uk.co.chrisjenx:calligraphy:2.2.0'
}
然后制作一个扩展应用程序的class并编写此代码:
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()
);
}
}
您应该在 assets/ 上创建 "New Directory" "fonts"(见下文),因此在该代码中 "your font path" 应该是 "fonts/SourceSansPro-Regular.ttf"。 (只是 "fonts..." 而不是 "/fonts.." 或 "assets..")
并在 activity class 中将此方法放在 onCreate 之前:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
你的清单文件最后应该是这样的:
<application
.
.
.
android:name=".App">
它会将整个 activity 更改为您的字体!简单干净!
在资产上,您应该 right-click 新目录,将其命名为 "fonts"。在取景器中将 .ttf
字体文件放在那里。
另外不要忘记在attrs.xml中添加以下两行,如果你没有attrs.xml文件,请在values.xml
中创建新文件
<attr format="string" name="fontPath"/>
<item name="calligraphy_tag_id" type="id"/>
我也尝试过字体覆盖,但最终这不是一个可靠的解决方案,遗憾的是覆盖字体需要更多的时间。你可以等待 Android 带有自定义字体的 O 出来,或者使用第三方库。
我遇到的最后一个解决方案是这个库 Caligraphy ,它很容易启动,让您可以使用任意数量的字体。在检查它的源代码时,我明白了为什么仅仅覆盖字体不起作用,所以即使你不打算使用它,我也建议你通读一遍..
祝你好运
试试下面的代码,对我有用,希望对你也有帮助。
public class BaseActivity extends AppCompatActivity {
private Typeface typeace;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
typeace = Typeface.createFromAsset(getAssets(), getResources().getString(R.string.font_name));
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
overrideFonts(this,getWindow().getDecorView());
}
private void overrideFonts(final Context context, final View v) {
try {
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
View child = vg.getChildAt(i);
overrideFonts(context, child);
}
} else if (v instanceof TextView) {
((TextView) v).setTypeface(typeace);
} else if (v instanceof EditText ) {
((EditText) v).setTypeface(typeace);
} else if (v instanceof Button) {
((Button) v).setTypeface(typeace);
}
} catch (Exception e) {
}
}
}
现在将此 BaseActivity 扩展到您的任何 Activity 或者您可以为正在使用的片段创建相同的 class。
注意:- 如果你想设置一些视图不同的字体,那么你必须以编程方式设置,如下所示
private Typeface typeface;
typeface = Typeface.createFromAsset(getAssets(), getResources().getString(R.string.font_name_bold));
tvUserName.setTypeface(typeface);
所以试试看,如果我能进一步帮助你,请告诉我
我所做的只是:
1: 将"new resource directory" 添加到RES 文件夹,从给定的drop-down 中选择RESOURCE TYPE 为"font",将新目录命名为"font" 并保存。
2: 将我的 "custom_font.ttf" 添加到刚刚创建的 FONT 文件夹中。
3: 在STYLES.XML
的应用程序基础主题中添加了我的自定义字体
完成。
您现在可以使用 android SDK 来完成,因为 Android 开发者官方 youtube 频道发布在 set/2017 here.
需要 API 23 级及以上。
您只需要将您的字体文件放在 res/font
文件夹中,并在您的 TextView
中引用它们,以防您需要具有 android:fontFamily
属性的特定字体。
如果您想在整个应用程序中使用基本字体,只需输入
<item name="android:fontFamily">@font/yourfontname</item>
在你的 styles.xml
您可以从 Android Studio 下载自定义字体,如果您愿意,也可以随时随地下载。所有这些你都可以在上面的视频中找到详细信息。
在主 folder.add 字体文件夹中创建资产文件夹。在字体文件夹中添加您的 .ttf 文件。
在您的应用主题中添加以下内容:
<item name="android:fontFamily">@font/roboto_regular</item>
<item name="fontFamily">@font/roboto_regular</item>
创建 class 作为 TypefaceUtil
import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import java.lang.reflect.Field;
public class TypefaceUtil {
/**
* Using reflection to override default typeface
* NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
* @param context to work with assets
* @param defaultFontNameToOverride for example "monospace"
* @param customFontFileNameInAssets file name of the font from assets
*/
public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
try {
final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);
final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
defaultFontTypefaceField.setAccessible(true);
defaultFontTypefaceField.set(null, customFontTypeface);
} catch (Exception e) {
Log.e("Can not set","Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
}
}
}
在应用程序 class 或启动器 activity 中调用它
TypefaceUtil.overrideFont(getApplicationContext(), "fonts/roboto_regular.ttf", "fonts/roboto_regular.ttf"); // font from assets: "assets/fonts/Roboto-Regular.ttf
Android 提供更简单和最好的解决方案,支持库 26+ 在 API 级别 14 上支持这些解决方案。 Fonts in XML 它还支持 字体系列 选项。
需要导入:
implementation "com.android.support:support-compat:<26+ version>"
按照这些简单的步骤,字体系列将毫无障碍地应用到您的应用中:
- 在 res
中创建一个 font 目录
- 将你的字体文件粘贴到 font
- Right-click 字体文件夹并转到新建 > 字体资源文件。出现新资源文件 window。
- 添加以下属性
<?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>
- 在上面的 xml 文件中。使用 app 仅用于使用支持库。否则,如果您的应用面向 API 级别 26+,您可以使用 android。
- 现在转到您的 styles.xml 并在您的主要样式中添加一行。
<item name="android:fontFamily">@font/opensans</item>
- 重要提示:仅当您使用支持库时才使用 AppCompatActivity。
或使用下面以编程方式设置字体
view.setTypeface(ResourcesCompat.getFont(context, R.font.opensans));
kotlin 的解决方法是这样
解决方案的要点https://gist.github.com/Johnyoat/040ca5224071d01b3f3dfc6cd4d026f7
第一步
将字体文件放在assets/fonts/your_font_file.ttf下
并创建一个名为 TypeFaceUtil
的 kotlin class
object TypefaceUtil{
fun overridefonts(context: Context, defaultFontToOverride:String, customFontFileNameInAssets:String){
try {
val customTypeface = Typeface.createFromAsset(context.assets,customFontFileNameInAssets)
val defaultTypefaceField = Typeface::class.java.getDeclaredField(defaultFontToOverride)
defaultTypefaceField.isAccessible = true
defaultTypefaceField.set(null,customTypeface)
}catch (e:Exception){
Timber.e("Cannot set font $customFontFileNameInAssets instead of $defaultFontToOverride")
}
}
}
第二步
然后在你的 onCreate
TypefaceUtil.overridefonts(this,"SERIF","fonts/font_file.ttf")
第三步
将此添加到您的风格中
<item name="android:typeface">serif</item>
- 开始时,您应该右键单击名称为
res
的项目资源,然后从 new
选项中选择 Android Resource Directory
和 select font
形成 Resource type
并按确定,这将创建字体目录以将您的字体放入其中。
- 将您的
.ttf
字体文件放在那里。
转到以下路径中存在的项目样式文件res/values/styles.xml
并添加这样的样式:
<style name="SansSerifFont">
<item name="android:fontFamily">sans-serif</item>
</style>
<style name="OpenSansFont">
<item name="android:fontFamily">@font/open_sans</item>
</style>
<style name="IranianSansFont">
<item name="android:fontFamily">@font/iranian_sans</item>
</style>
<style name="BYekanFont">
<item name="android:fontFamily">@font/b_yekan</item>
</style>
<style name="DroidArabicFont">
<item name="android:fontFamily">@font/droid_arabic</item>
</style>
转到您的代码并像这样编写 class 以更改整个应用程序字体:
public class AppFontManager {
private AppCompatActivity appCompatActivity;
public static final String SANS_SERIF_APP_FONT = "sans_serif";
public static final String B_YEKAN_APP_FONT = "b_yekan";
public static final String DROID_ARABIC_APP_FONT = "droid_arabic";
public static final String IRANIAN_SANS_APP_FONT = "iranian_sans";
public static final String OPEN_SANS_APP_FONT = "open_sans";
public AppAppearanceManager(AppCompatActivity appCompatActivity) {
this.appCompatActivity = appCompatActivity;
}
public void setFont(String fontName){
switch (fontName){
case SANS_SERIF_APP_FONT:{
appCompatActivity.getTheme().applyStyle(R.style.SansSerifFont, true);
break;
}
case B_YEKAN_APP_FONT:{
appCompatActivity.getTheme().applyStyle(R.style.BYekanFont, true);
break;
}
case DROID_ARABIC_APP_FONT:{
appCompatActivity.getTheme().applyStyle(R.style.DroidArabicFont, true);
break;
}
case IRANIAN_SANS_APP_FONT:{
appCompatActivity.getTheme().applyStyle(R.style.IranianSansFont, true);
break;
}
case OPEN_SANS_APP_FONT:{
appCompatActivity.getTheme().applyStyle(R.style.OpenSansFont, true);
break;
}
}
}
}
因为字体应该为每个活动单独设置,我更喜欢为它写一个class以获得更干净的代码。
然后在activityonCreate之前调用class方法super.onCreate(savedInstanceState)
:
@Override
protected void onCreate(Bundle savedInstanceState) {
new AppAppearanceManager(this).setFont(APP_DEFAULT_FONT);
super.onCreate(savedInstanceState);
// Do you stuff there...
}
请记住,如果您想在 运行时 期间更改字体,请在 SharedPreferences
等中写入所选字体,然后将所选字体传递给所有活动 setFont
如上。
字体名称应小写,以便在应用程序和工作中显示。
这就是我将字体 ttf 应用到整个应用程序的方式
1.在res目录下新建一个名为font的目录
2. 复制字体 ttf 例如varela.ttf 在此字体目录中
3.检查AndroidManifest.xml
中的主题
<application
android:theme="@style/Theme.MyAppTheme">
<activity
......
</activity>
</application>
4. 转到 themes.xml inside values 目录并在 AndroidManifest.xml
中引用的基本主题样式中添加带有项目标签的字体
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MyAppTheme"
parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="android:fontFamily">@font/varela</item>
</style>
</resources>
是否可以在 Android 应用程序中设置自定义字体?
我尝试了 here 发布的内容,但我不知道我的 extends Application
class 在哪里...
有什么帮助吗?
编辑:
我尝试了以下方法:
- 添加资产文件夹并在其中插入字体,如下所示:
添加从
Application
扩展的新 class
从我的
AndroidManifest.xml
调用这个新的 class。我去我的风格加了
MyApp.java:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
FontsOverride.setDefaultFont(this, "DEFAULT", "raleway_regular.ttf");
// This FontsOverride comes from the example I posted above
}
}
AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".MyApp"
android:theme="@style/AppTheme">
....
styles.xml:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:fontFamily">default</item>
</style>
但是我的字体还是没有改变...有什么想法吗?
然后 MyApp
class 被调用。但是对我的字体没有影响...
EDIT2: 我意识到在为我的按钮设置自定义样式后,我的按钮应用了自定义字体。这是我的自定义按钮样式:
<style name="MyButtonStyle" parent="Widget.AppCompat.Button">
<item name="textAllCaps">false</item>
<item name="android:textAllCaps">false</item>
</style>
这是现在的样子:
所以:我的按钮正在应用样式,而不是 TextView
。知道为什么我的自定义字体没有应用于应用程序中的所有项目吗?
您似乎在 styles.xml
中使用 android:fontFamily
而不是 android:typeface
。
尝试更换
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:fontFamily">default</item>
</style>
和
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:typeface">default</item>
</style>
写一个class
public class MyApp extends Application{
// Put the onCreate code as you obtained from the post link you reffered
}
现在接下来的事情是 AndroidManifest.xml 应用程序标签,为您的应用程序命名 class。在本例中是 MyApp
<application
android:name=".MyApp"
...
>
...
</application>
所以每次打开应用程序时,都会调用MyApp class的onCreate方法,并设置字体。
更新 将字体文件放在assets/fonts/your_font_file.ttf
下将此行放在应用程序的 onCreate 方法下 class(MyApp)
TypefaceUtil.overrideFont(getApplicationContext(), "SERIF", "fonts/your_font_file.ttf");
TypefaceUtil 的源文件
public class TypefaceUtil {
/**
* Using reflection to override default typeface
* NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
*
* @param context to work with assets
* @param defaultFontNameToOverride for example "monospace"
* @param customFontFileNameInAssets file name of the font from assets
*/
public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Map<String, Typeface> newMap = new HashMap<String, Typeface>();
newMap.put("serif", customFontTypeface);
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 defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
defaultFontTypefaceField.setAccessible(true);
defaultFontTypefaceField.set(null, customFontTypeface);
} catch (Exception e) {
Log.e(TypefaceUtil.class.getSimpleName(), "Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
}
}
}
}
现在更新您的 style.xml 文件
在清单文件
中将您的 activity 包含的样式放在下面一行 <item name="android:typeface">serif</item>
希望对您有所帮助
首先,创建一个新的 class 来覆盖您想要自定义的任何视图。 (例如,想要一个带有自定义字体的按钮?扩展 Button
)。例如:
public class CustomButton extends Button {
private final static int ROBOTO = 0;
private final static int ROBOTO_CONDENSED = 1;
public CustomButton(Context context) {
super(context);
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context, attrs); //I'll explain this method later
}
public CustomButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
parseAttributes(context, attrs);
}
}
现在,如果您没有,请在 res/values/attrs.xml
下添加一个 XML 文档,然后添加:
<resources>
<!-- Define the values for the attribute -->
<attr name="typeface" format="enum">
<enum name="roboto" value="0"/>
<enum name="robotoCondensed" value="1"/>
</attr>
<!-- Tell Android that the class "CustomButton" can be styled,
and which attributes it supports -->
<declare-styleable name="CustomButton">
<attr name="typeface"/>
</declare-styleable>
</resources>
好吧,让我们回到前面的 parseAttributes()
方法:
private void parseAttributes(Context context, AttributeSet attrs) {
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomButton);
//The value 0 is a default, but shouldn't ever be used since the attr is an enum
int typeface = values.getInt(R.styleable.CustomButton_typeface, 0);
switch(typeface) {
case ROBOTO: default:
//You can instantiate your typeface anywhere, I would suggest as a
//singleton somewhere to avoid unnecessary copies
setTypeface(roboto);
break;
case ROBOTO_CONDENSED:
setTypeface(robotoCondensed);
break;
}
values.recycle();
}
现在你已经准备好了。您可以为任何东西添加更多属性(您可以为 typefaceStyle 添加另一个属性 -- 粗体、斜体等)但现在让我们看看如何使用它:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.yourpackage.name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.yourpackage.name.CustomButton
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me!"
custom:typeface="roboto" />
</LinearLayout>
xmlns:custom
行实际上可以是任何内容,但惯例如上所示。重要的是它是唯一的,这就是使用包名称的原因。现在您只需为属性使用 custom:
前缀,为 android 属性使用 android:
前缀。
最后一件事:如果你想在样式中使用它 (res/values/styles.xml
),你应该 而不是 添加 xmlns:custom
行。仅引用不带前缀的属性名称:
<style name="MyStyle>
<item name="typeface">roboto</item>
</style>
如果您遵循第一个主题,这应该有效:Here
是的,有反思。这有效(based on this answer):
(注意:由于不支持自定义字体,这是一种解决方法,所以如果您想改变这种情况,请在此处为 up-vote 和 android 问题加注星标)。注意:不要在那个问题上留下 "me too" 评论,当你这样做时,所有看过它的人都会收到一封电子邮件。所以请"star"。
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();
}
}
}
然后您需要重载一些默认字体,例如在应用程序中 class:
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>
API 21 Android 5.0
我调查了评论中的报告,说它不起作用,而且似乎与主题不兼容 android:Theme。Material.Light。
如果该主题对您不重要,请使用较旧的主题,例如:
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:typeface">monospace</item>
</style>
编辑
uk.co.chrisjenx:calligraphy
不再为最新 android 版本维护更多的替代版本
https://github.com/InflationX/Calligraphy
dependencies {
implementation 'io.github.inflationx:calligraphy3:3.1.1'
implementation 'io.github.inflationx:viewpump:2.0.3'
}
将您的自定义字体添加到资产/
用法
默认字体
在您的应用程序 class 中的 #onCreate() 方法中使用 CalligraphyConfig 定义您的默认字体,并将其传递给您添加到 ViewPump 构建器的 CalligraphyInterceptor。
@Override
public void onCreate() {
super.onCreate();
ViewPump.init(ViewPump.builder()
.addInterceptor(new CalligraphyInterceptor(
new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/Roboto-RobotoRegular.ttf")
.setFontAttrId(R.attr.fontPath)
.build()))
.build());
//....
}
注入上下文:包装 Activity 上下文:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
}
自定义样式
<style name="TextViewCustomFont">
<item name="fontPath">fonts/RobotoCondensed-Regular.ttf</item>
</style>
对于主题
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:textViewStyle">@style/AppTheme.Widget.TextView</item>
</style>
<style name="AppTheme.Widget"/>
<style name="AppTheme.Widget.TextView" parent="android:Widget.Holo.Light.TextView">
<item name="fontPath">fonts/Roboto-ThinItalic.ttf</item>
</style>
解决方案下方的开发人员不再维护
android:Calligraphy
中有一个很棒的自定义字体库
这是一个如何使用它的示例。
在 Gradle 中,您需要将此行放入应用程序的 build.gradle 文件中:
dependencies {
compile 'uk.co.chrisjenx:calligraphy:2.2.0'
}
然后制作一个扩展应用程序的class并编写此代码:
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()
);
}
}
您应该在 assets/ 上创建 "New Directory" "fonts"(见下文),因此在该代码中 "your font path" 应该是 "fonts/SourceSansPro-Regular.ttf"。 (只是 "fonts..." 而不是 "/fonts.." 或 "assets..")
并在 activity class 中将此方法放在 onCreate 之前:
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
你的清单文件最后应该是这样的:
<application
.
.
.
android:name=".App">
它会将整个 activity 更改为您的字体!简单干净!
在资产上,您应该 right-click 新目录,将其命名为 "fonts"。在取景器中将 .ttf
字体文件放在那里。
另外不要忘记在attrs.xml中添加以下两行,如果你没有attrs.xml文件,请在values.xml
中创建新文件 <attr format="string" name="fontPath"/>
<item name="calligraphy_tag_id" type="id"/>
我也尝试过字体覆盖,但最终这不是一个可靠的解决方案,遗憾的是覆盖字体需要更多的时间。你可以等待 Android 带有自定义字体的 O 出来,或者使用第三方库。
我遇到的最后一个解决方案是这个库 Caligraphy ,它很容易启动,让您可以使用任意数量的字体。在检查它的源代码时,我明白了为什么仅仅覆盖字体不起作用,所以即使你不打算使用它,我也建议你通读一遍..
祝你好运
试试下面的代码,对我有用,希望对你也有帮助。
public class BaseActivity extends AppCompatActivity {
private Typeface typeace;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
typeace = Typeface.createFromAsset(getAssets(), getResources().getString(R.string.font_name));
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
overrideFonts(this,getWindow().getDecorView());
}
private void overrideFonts(final Context context, final View v) {
try {
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
View child = vg.getChildAt(i);
overrideFonts(context, child);
}
} else if (v instanceof TextView) {
((TextView) v).setTypeface(typeace);
} else if (v instanceof EditText ) {
((EditText) v).setTypeface(typeace);
} else if (v instanceof Button) {
((Button) v).setTypeface(typeace);
}
} catch (Exception e) {
}
}
}
现在将此 BaseActivity 扩展到您的任何 Activity 或者您可以为正在使用的片段创建相同的 class。
注意:- 如果你想设置一些视图不同的字体,那么你必须以编程方式设置,如下所示
private Typeface typeface;
typeface = Typeface.createFromAsset(getAssets(), getResources().getString(R.string.font_name_bold));
tvUserName.setTypeface(typeface);
所以试试看,如果我能进一步帮助你,请告诉我
我所做的只是:
1: 将"new resource directory" 添加到RES 文件夹,从给定的drop-down 中选择RESOURCE TYPE 为"font",将新目录命名为"font" 并保存。
2: 将我的 "custom_font.ttf" 添加到刚刚创建的 FONT 文件夹中。
3: 在STYLES.XML
的应用程序基础主题中添加了我的自定义字体完成。
您现在可以使用 android SDK 来完成,因为 Android 开发者官方 youtube 频道发布在 set/2017 here.
需要 API 23 级及以上。
您只需要将您的字体文件放在 res/font
文件夹中,并在您的 TextView
中引用它们,以防您需要具有 android:fontFamily
属性的特定字体。
如果您想在整个应用程序中使用基本字体,只需输入
<item name="android:fontFamily">@font/yourfontname</item>
在你的 styles.xml
您可以从 Android Studio 下载自定义字体,如果您愿意,也可以随时随地下载。所有这些你都可以在上面的视频中找到详细信息。
在主 folder.add 字体文件夹中创建资产文件夹。在字体文件夹中添加您的 .ttf 文件。
在您的应用主题中添加以下内容:
<item name="android:fontFamily">@font/roboto_regular</item>
<item name="fontFamily">@font/roboto_regular</item>
创建 class 作为 TypefaceUtil
import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import java.lang.reflect.Field;
public class TypefaceUtil {
/**
* Using reflection to override default typeface
* NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
* @param context to work with assets
* @param defaultFontNameToOverride for example "monospace"
* @param customFontFileNameInAssets file name of the font from assets
*/
public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
try {
final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);
final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
defaultFontTypefaceField.setAccessible(true);
defaultFontTypefaceField.set(null, customFontTypeface);
} catch (Exception e) {
Log.e("Can not set","Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
}
}
}
在应用程序 class 或启动器 activity 中调用它
TypefaceUtil.overrideFont(getApplicationContext(), "fonts/roboto_regular.ttf", "fonts/roboto_regular.ttf"); // font from assets: "assets/fonts/Roboto-Regular.ttf
Android 提供更简单和最好的解决方案,支持库 26+ 在 API 级别 14 上支持这些解决方案。 Fonts in XML 它还支持 字体系列 选项。
需要导入:
implementation "com.android.support:support-compat:<26+ version>"
按照这些简单的步骤,字体系列将毫无障碍地应用到您的应用中:
- 在 res 中创建一个 font 目录
- 将你的字体文件粘贴到 font
- Right-click 字体文件夹并转到新建 > 字体资源文件。出现新资源文件 window。
- 添加以下属性
<?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>
- 在上面的 xml 文件中。使用 app 仅用于使用支持库。否则,如果您的应用面向 API 级别 26+,您可以使用 android。
- 现在转到您的 styles.xml 并在您的主要样式中添加一行。
<item name="android:fontFamily">@font/opensans</item>
- 重要提示:仅当您使用支持库时才使用 AppCompatActivity。
或使用下面以编程方式设置字体
view.setTypeface(ResourcesCompat.getFont(context, R.font.opensans));
kotlin 的解决方法是这样
解决方案的要点https://gist.github.com/Johnyoat/040ca5224071d01b3f3dfc6cd4d026f7
第一步
将字体文件放在assets/fonts/your_font_file.ttf下 并创建一个名为 TypeFaceUtil
的 kotlin class object TypefaceUtil{
fun overridefonts(context: Context, defaultFontToOverride:String, customFontFileNameInAssets:String){
try {
val customTypeface = Typeface.createFromAsset(context.assets,customFontFileNameInAssets)
val defaultTypefaceField = Typeface::class.java.getDeclaredField(defaultFontToOverride)
defaultTypefaceField.isAccessible = true
defaultTypefaceField.set(null,customTypeface)
}catch (e:Exception){
Timber.e("Cannot set font $customFontFileNameInAssets instead of $defaultFontToOverride")
}
}
}
第二步
然后在你的 onCreate
TypefaceUtil.overridefonts(this,"SERIF","fonts/font_file.ttf")
第三步
将此添加到您的风格中
<item name="android:typeface">serif</item>
- 开始时,您应该右键单击名称为
res
的项目资源,然后从new
选项中选择Android Resource Directory
和 selectfont
形成Resource type
并按确定,这将创建字体目录以将您的字体放入其中。
- 将您的
.ttf
字体文件放在那里。
转到以下路径中存在的项目样式文件
res/values/styles.xml
并添加这样的样式:<style name="SansSerifFont"> <item name="android:fontFamily">sans-serif</item> </style> <style name="OpenSansFont"> <item name="android:fontFamily">@font/open_sans</item> </style> <style name="IranianSansFont"> <item name="android:fontFamily">@font/iranian_sans</item> </style> <style name="BYekanFont"> <item name="android:fontFamily">@font/b_yekan</item> </style> <style name="DroidArabicFont"> <item name="android:fontFamily">@font/droid_arabic</item> </style>
转到您的代码并像这样编写 class 以更改整个应用程序字体:
public class AppFontManager { private AppCompatActivity appCompatActivity; public static final String SANS_SERIF_APP_FONT = "sans_serif"; public static final String B_YEKAN_APP_FONT = "b_yekan"; public static final String DROID_ARABIC_APP_FONT = "droid_arabic"; public static final String IRANIAN_SANS_APP_FONT = "iranian_sans"; public static final String OPEN_SANS_APP_FONT = "open_sans"; public AppAppearanceManager(AppCompatActivity appCompatActivity) { this.appCompatActivity = appCompatActivity; } public void setFont(String fontName){ switch (fontName){ case SANS_SERIF_APP_FONT:{ appCompatActivity.getTheme().applyStyle(R.style.SansSerifFont, true); break; } case B_YEKAN_APP_FONT:{ appCompatActivity.getTheme().applyStyle(R.style.BYekanFont, true); break; } case DROID_ARABIC_APP_FONT:{ appCompatActivity.getTheme().applyStyle(R.style.DroidArabicFont, true); break; } case IRANIAN_SANS_APP_FONT:{ appCompatActivity.getTheme().applyStyle(R.style.IranianSansFont, true); break; } case OPEN_SANS_APP_FONT:{ appCompatActivity.getTheme().applyStyle(R.style.OpenSansFont, true); break; } } } }
因为字体应该为每个活动单独设置,我更喜欢为它写一个class以获得更干净的代码。
然后在activityonCreate之前调用class方法
super.onCreate(savedInstanceState)
:@Override protected void onCreate(Bundle savedInstanceState) { new AppAppearanceManager(this).setFont(APP_DEFAULT_FONT); super.onCreate(savedInstanceState); // Do you stuff there... }
请记住,如果您想在 运行时 期间更改字体,请在
SharedPreferences
等中写入所选字体,然后将所选字体传递给所有活动setFont
如上。
字体名称应小写,以便在应用程序和工作中显示。
这就是我将字体 ttf 应用到整个应用程序的方式
1.在res目录下新建一个名为font的目录
2. 复制字体 ttf 例如varela.ttf 在此字体目录中
3.检查AndroidManifest.xml
中的主题 <application
android:theme="@style/Theme.MyAppTheme">
<activity
......
</activity>
</application>
4. 转到 themes.xml inside values 目录并在 AndroidManifest.xml
中引用的基本主题样式中添加带有项目标签的字体 <resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MyAppTheme"
parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="android:fontFamily">@font/varela</item>
</style>
</resources>