如何在 ActionBar 标题中设置自定义字体?
Posted
技术标签:
【中文标题】如何在 ActionBar 标题中设置自定义字体?【英文标题】:How to Set a Custom Font in the ActionBar Title? 【发布时间】:2012-01-26 07:41:54 【问题描述】:如何(如果可能)在我的资产文件夹中使用字体在 ActionBar 标题文本(仅 - 不是选项卡文本)中设置自定义字体?我不想使用 android:logo 选项。
【问题讨论】:
【参考方案1】:试试这个
TextView headerText= new TextView(getApplicationContext());
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT);
headerText.setLayoutParams(lp);
headerText.setText("Welcome!");
headerText.setTextSize(20);
headerText.setTextColor(Color.parseColor("#FFFFFF"));
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/wesfy_regular.ttf");
headerText.setTypeface(tf);
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
getSupportActionBar().setCustomView(headerText);
【讨论】:
【参考方案2】:不需要自定义文本视图!
首先,在您的 java 代码中禁用工具栏中的标题: getSupportActionBar().setDisplayShowTitleEnabled(false);
然后,只需在工具栏内添加一个 TextView :
<android.support.v7.widget.Toolbar
android:layout_
android:layout_
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
<TextView
android:layout_
android:layout_
android:text="@string/app_name"
android:textSize="18sp"
android:fontFamily="@font/roboto" />
</android.support.v7.widget.Toolbar>
【讨论】:
这不适用于最新的导航 UI 喷气背包库【参考方案3】: ActionBar actionBar = getSupportActionBar();
TextView tv = new TextView(getApplicationContext());
Typeface typeface = ResourcesCompat.getFont(this, R.font.monotype_corsiva);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, // Width of TextView
RelativeLayout.LayoutParams.WRAP_CONTENT); // Height of TextView
tv.setLayoutParams(lp);
tv.setText("Your Text"); // ActionBar title text
tv.setTextSize(25);
tv.setTextColor(Color.WHITE);
tv.setTypeface(typeface, typeface.ITALIC);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setCustomView(tv);
【讨论】:
太棒了效果很好我怎样才能让这个应用栏进入中心? 像魅力一样工作 .. 只需将typeface.ITALIC
替换为 Typeface.ITALIC
就不会出现静态成员警告
05/02/2021 对我来说唯一可行的解决方案。谢谢大佬。【参考方案4】:
从 Android Support Library v26 + Android Studio 3.0 开始,这个过程变得轻而易举!!
按照以下步骤更改工具栏标题的字体:
-
阅读Downloadable Fonts 并从列表中选择任何字体(我的建议)或根据Fonts in XML 将自定义字体加载到
res > font
在res > values > styles
中,粘贴以下内容(在这里发挥你的想象力!)
<style name="TitleBarTextAppearance" parent="android:TextAppearance">
<item name="android:fontFamily">@font/your_desired_font</item>
<item name="android:textSize">23sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@android:color/white</item>
</style>
在您的工具栏属性app:titleTextAppearance="@style/TextAppearance.TabsFont"
中插入一个新行,如下所示
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_
android:layout_
android:background="?attr/colorPrimary"
app:titleTextAppearance="@style/TitleBarTextAppearance"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
享受自定义操作栏标题字体样式!!
【讨论】:
这对于工具栏来说非常有用。有什么方法可以在整个应用程序范围内执行此操作,例如当您在新活动中使用默认应用程序栏时? 这也适用于折叠标题应用程序:collapsedTitleTextAppearance="@style/Style_Title"【参考方案5】:我刚刚在 onCreate() 函数中做了以下操作:
TypefaceSpan typefaceSpan = new TypefaceSpan("font_to_be_used");
SpannableString str = new SpannableString("toolbar_text");
str.setSpan(typefaceSpan,0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
getSupportActionBar().setTitle(str);
我正在使用支持库,如果您不使用它们,我想您应该切换到 getActionBar() 而不是 getSupportActionBar()。
在 Android Studio 3 中,您可以按照此说明 https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html 添加自定义字体,然后在“font_to_be_used”中使用您新添加的字体
【讨论】:
【参考方案6】:Calligraphy 库可让您通过应用主题设置自定义字体,该字体也适用于操作栏。
<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>
激活 Calligraphy 所需要的只是将它附加到您的 Activity 上下文中:
@Override
protected void attachBaseContext(Context newBase)
super.attachBaseContext(new CalligraphyContextWrapper(newBase));
默认的自定义属性是fontPath
,但您可以通过在应用程序类中使用CalligraphyConfig.Builder
对其进行初始化来为路径提供自己的自定义属性。不鼓励使用android:fontFamily
。
【讨论】:
此解决方案的最低 API 16 minSdk 7 根据项目的构建文件,但我在 minSdk 18 项目中使用它并且没有对其进行任何进一步检查。使用的违规方法是什么? 它的最低API 7,只是例子是API16。它支持 appcompat-v7+【参考方案7】:更新正确答案。
首先:将标题设置为 false,因为我们使用的是自定义视图
actionBar.setDisplayShowTitleEnabled(false);
其次:创建titleview.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="@android:color/transparent" >
<TextView
android:id="@+id/title"
android:layout_
android:layout_
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:textSize="20dp"
android:maxLines="1"
android:ellipsize="end"
android:text="" />
</RelativeLayout>
最后:
//font file must be in the phone db so you have to create download file code
//check the code on the bottom part of the download file code.
TypeFace font = Typeface.createFromFile("/storage/emulated/0/Android/data/"
+ BuildConfig.APPLICATION_ID + "/files/" + "font name" + ".ttf");
if(font != null)
LayoutInflater inflator = LayoutInflater.from(this);
View v = inflator.inflate(R.layout.titleview, null);
TextView titleTv = ((TextView) v.findViewById(R.id.title));
titleTv.setText(title);
titleTv.setTypeface(font);
actionBar.setCustomView(v);
else
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(" " + title); // Need to add a title
下载字体文件:因为我将文件存储到云中,所以我有下载链接。
/**downloadFile*/
public void downloadFile()
String DownloadUrl = //url here
File file = new File("/storage/emulated/0/Android/data/" + BuildConfig.APPLICATION_ID + "/files/");
File[] list = file.listFiles();
if(list == null || list.length <= 0)
BroadcastReceiver onComplete = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent)
try
showContentFragment(false);
catch (Exception e)
;
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DownloadUrl));
request.setVisibleInDownloadsUi(false);
request.setDestinationInExternalFilesDir(this, null, ModelManager.getInstance().getCurrentApp().getRegular_font_name() + ".ttf");
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
else
for (File files : list)
if (!files.getName().equals("font_name" + ".ttf"))
BroadcastReceiver onComplete = new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent)
try
showContentFragment(false);
catch (Exception e)
;
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DownloadUrl));
request.setVisibleInDownloadsUi(false);
request.setDestinationInExternalFilesDir(this, null, "font_name" + ".ttf");
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
else
showContentFragment(false);
break;
【讨论】:
【参考方案8】:我们需要使用反射来实现这一点
final int titleId = activity.getResources().getIdentifier("action_bar_title", "id", "android");
final TextView title;
if (activity.findViewById(titleId) != null)
title = (TextView) activity.findViewById(titleId);
title.setTextColor(Color.BLACK);
title.setTextColor(configs().getColor(ColorKey.GENERAL_TEXT));
title.setTypeface(configs().getTypeface());
else
try
Field f = bar.getClass().getDeclaredField("mTitleTextView");
f.setAccessible(true);
title = (TextView) f.get(bar);
title.setTextColor(Color.BLACK);
title.setTypeface(configs().getTypeface());
catch (NoSuchFieldException e)
catch (IllegalAccessException e)
【讨论】:
【参考方案9】:使用支持库中的新工具栏设计您自己的操作栏或使用以下代码
膨胀 Textview 不是一个好的选择,试试 Spannable String builder
Typeface font2 = Typeface.createFromAsset(getAssets(), "fonts/<your font in assets folder>");
SpannableStringBuilder SS = new SpannableStringBuilder("MY Actionbar Tittle");
SS.setSpan (new CustomTypefaceSpan("", font2), 0, SS.length(),Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
actionBar.setTitle(ss);
复制到下面的类
public class CustomTypefaceSpan extends TypefaceSpan
private final Typeface newType;
public CustomTypefaceSpan(String family, Typeface type)
super(family);
newType = type;
@Override
public void updateDrawState(TextPaint ds)
applyCustomTypeFace(ds, newType);
@Override
public void updateMeasureState(TextPaint paint)
applyCustomTypeFace(paint, newType);
private static void applyCustomTypeFace(Paint paint, Typeface tf)
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null)
oldStyle = 0;
else
oldStyle = old.getStyle();
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0)
paint.setFakeBoldText(true);
if ((fake & Typeface.ITALIC) != 0)
paint.setTextSkewX(-0.25f);
paint.setTypeface(tf);
【讨论】:
【参考方案10】:试试这个
public void findAndSetFont()
getActionBar().setTitle("SOME TEST TEXT");
scanForTextViewWithText(this,"SOME TEST TEXT",new SearchTextViewInterface()
@Override
public void found(TextView title)
);
public static void scanForTextViewWithText(Activity activity,String searchText, SearchTextViewInterface searchTextViewInterface)
if(activity == null|| searchText == null || searchTextViewInterface == null)
return;
View view = activity.findViewById(android.R.id.content).getRootView();
searchForTextViewWithTitle(view, searchText, searchTextViewInterface);
private static void searchForTextViewWithTitle(View view, String searchText, SearchTextViewInterface searchTextViewInterface)
if (view instanceof ViewGroup)
ViewGroup g = (ViewGroup) view;
int count = g.getChildCount();
for (int i = 0; i < count; i++)
searchForTextViewWithTitle(g.getChildAt(i), searchText, searchTextViewInterface);
else if (view instanceof TextView)
TextView textView = (TextView) view;
if(textView.getText().toString().equals(searchText))
if(searchTextViewInterface!=null)
searchTextViewInterface.found(textView);
public interface SearchTextViewInterface
void found(TextView title);
【讨论】:
【参考方案11】:如果你想为整个 Activity 中的所有 TextViews 设置字体,你可以使用这样的东西:
public static void setTypefaceToAll(Activity activity)
View view = activity.findViewById(android.R.id.content).getRootView();
setTypefaceToAll(view);
public static void setTypefaceToAll(View view)
if (view instanceof ViewGroup)
ViewGroup g = (ViewGroup) view;
int count = g.getChildCount();
for (int i = 0; i < count; i++)
setTypefaceToAll(g.getChildAt(i));
else if (view instanceof TextView)
TextView tv = (TextView) view;
setTypeface(tv);
public static void setTypeface(TextView tv)
TypefaceCache.setFont(tv, TypefaceCache.FONT_KOODAK);
还有字体缓存:
import java.util.TreeMap;
import android.graphics.Typeface;
import android.widget.TextView;
public class TypefaceCache
//Font names from asset:
public static final String FONT_ROBOTO_REGULAR = "fonts/Roboto-Regular.ttf";
public static final String FONT_KOODAK = "fonts/Koodak.ttf";
private static TreeMap<String, Typeface> fontCache = new TreeMap<String, Typeface>();
public static Typeface getFont(String fontName)
Typeface tf = fontCache.get(fontName);
if(tf == null)
try
tf = Typeface.createFromAsset(MyApplication.getAppContext().getAssets(), fontName);
catch (Exception e)
return null;
fontCache.put(fontName, tf);
return tf;
public static void setFont(TextView tv, String fontName)
tv.setTypeface(getFont(fontName));
【讨论】:
【参考方案12】:我同意这并不完全受支持,但这就是我所做的。您可以为操作栏使用自定义视图(它将显示在您的图标和操作项之间)。我正在使用自定义视图,并且禁用了本机标题。我的所有活动都继承自一个活动,该活动在 onCreate 中有以下代码:
this.getActionBar().setDisplayShowCustomEnabled(true);
this.getActionBar().setDisplayShowTitleEnabled(false);
LayoutInflater inflator = LayoutInflater.from(this);
View v = inflator.inflate(R.layout.titleview, null);
//if you need to customize anything else about the text, do it here.
//I'm using a custom TextView with a custom font in my layout xml so all I need to do is set title
((TextView)v.findViewById(R.id.title)).setText(this.getTitle());
//assign the view to the actionbar
this.getActionBar().setCustomView(v);
而我的布局 xml(上面代码中的 R.layout.titleview)看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="@android:color/transparent" >
<com.your.package.CustomTextView
android:id="@+id/title"
android:layout_
android:layout_
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:textSize="20dp"
android:maxLines="1"
android:ellipsize="end"
android:text="" />
</RelativeLayout>
【讨论】:
这适用于标题,但如果您想要标题和选项卡,它会将自定义视图放置在选项卡的右侧,而不是像标题那样左侧。我希望能够更改实际标题。 很好的解决方案。如果您需要一个允许在 XML 中指定字体的自定义文本视图类,请试试我的! github.com/tom-dignan/nifty -- 很简单。 此代码是否必须在 onCreate() 中?我需要在我的活动之外动态设置它... 您需要动态更改字体吗?还是您只是想在字体已经自定义后更改标题? 这行得通,但它的工作量很大。另外:您失去了标准标题的一些功能,例如在单击图标时突出显示它......自定义标题并不意味着用于重新创建标准标题布局,只是为了更改字体......【参考方案13】:以下代码适用于所有版本。我确实在带有姜饼的设备以及 JellyBean 设备上检查了这一点
private void actionBarIdForAll()
int titleId = 0;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
titleId = getResources().getIdentifier("action_bar_title", "id", "android");
else
// This is the id is from your app's generated R class when ActionBarActivity is used for SupportActionBar
titleId = R.id.action_bar_title;
if(titleId>0)
// Do whatever you want ? It will work for all the versions.
// 1. Customize your fonts
// 2. Infact, customize your whole title TextView
TextView titleView = (TextView)findViewById(titleId);
titleView.setText("RedoApp");
titleView.setTextColor(Color.CYAN);
【讨论】:
这适用于我在 ActionBar 和 AppCompat ActionBar 上。但后者仅在我尝试在 onCreate() 之后找到标题视图时才有效,因此例如将其放置到 onPostCreate() 就可以了。【参考方案14】:int titleId = getResources().getIdentifier("action_bar_title", "id",
"android");
TextView yourTextView = (TextView) findViewById(titleId);
yourTextView.setTextColor(getResources().getColor(R.color.black));
yourTextView.setTypeface(face);
【讨论】:
这应该是问题的首选答案。效果很好,也适用于“action_bar_subtitle”!谢谢! 如果安卓开发者在较新版本中将资源ID从“action_bar_title”更改为其他名称,那么这将不起作用。这就是为什么它没有被投票的原因。 适用于 api >3.0 但不适用于 appcompat 的 2.x 这确实改变了字体和一切。但是当我转到下一个活动并按回时,字体会恢复。我猜这与 ActionBar 属性有关。 @Digit:这对“Holo 主题”很有效,但不适用于“Material Theme”(android L)。找到了titleId,但textview为null..有什么想法可以解决这个问题吗?谢谢!【参考方案15】:您可以使用自定义 TypefaceSpan
类来执行此操作。它优于上面提到的customView
方法,因为它在使用其他操作栏元素(如扩展操作视图)时不会中断。
这样一个类的使用看起来像这样:
SpannableString s = new SpannableString("My Title");
s.setSpan(new TypefaceSpan(this, "MyTypeface.otf"), 0, s.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Update the action bar title with the TypefaceSpan instance
ActionBar actionBar = getActionBar();
actionBar.setTitle(s);
自定义TypefaceSpan
类被传递给您的活动上下文和assets/fonts
目录中的字体名称。它加载文件并在内存中缓存一个新的Typeface
实例。 TypefaceSpan
的完整实现非常简单:
/**
* Style a @link Spannable with a custom @link Typeface.
*
* @author Tristan Waddington
*/
public class TypefaceSpan extends MetricAffectingSpan
/** An <code>LruCache</code> for previously loaded typefaces. */
private static LruCache<String, Typeface> sTypefaceCache =
new LruCache<String, Typeface>(12);
private Typeface mTypeface;
/**
* Load the @link Typeface and apply to a @link Spannable.
*/
public TypefaceSpan(Context context, String typefaceName)
mTypeface = sTypefaceCache.get(typefaceName);
if (mTypeface == null)
mTypeface = Typeface.createFromAsset(context.getApplicationContext()
.getAssets(), String.format("fonts/%s", typefaceName));
// Cache the loaded Typeface
sTypefaceCache.put(typefaceName, mTypeface);
@Override
public void updateMeasureState(TextPaint p)
p.setTypeface(mTypeface);
// Note: This flag is required for proper typeface rendering
p.setFlags(p.getFlags() | Paint.SUBPIXEL_TEXT_FLAG);
@Override
public void updateDrawState(TextPaint tp)
tp.setTypeface(mTypeface);
// Note: This flag is required for proper typeface rendering
tp.setFlags(tp.getFlags() | Paint.SUBPIXEL_TEXT_FLAG);
只需将上述类复制到您的项目中,并在您的活动的onCreate
方法中实现它,如上所示。
【讨论】:
不错的答案。令人高兴的是,您还展示了一种缓存字体元素的方法。 这太棒了。一个问题 - 如果textAllCaps
属性在底层 TextView 上设置为 true(例如,通过主题),那么自定义字体将不会出现。当我将此技术应用于操作栏选项卡项时,这对我来说是个问题。
请注意,该类的实现假定您将字体文件放在assets/fonts/
中。如果您只是将 .ttf/.otf 文件放在 assets 下而不是子文件夹中,则应相应地修改以下代码行:String.format("fonts/%s", typefaceName)
。我花了 10 分钟试图弄清楚。如果你不这样做,你会得到java.lang.RuntimeException: Unable to start activity ComponentInfocom.your.pckage: java.lang.RuntimeException: native typeface cannot be made
在启动应用程序的那一刻,默认的标题样式是可见的,大约 1 秒后自定义样式出现。糟糕的用户界面...
这是一个很好的答案,帮助了我很多。我要添加的一项改进是将缓存机制移到 TypefaceSpan 之外的自己的类中。我遇到了其他情况,我使用的是没有跨度的字体,这让我也可以在这些情况下利用缓存。【参考方案16】:
要添加到@Sam_D 的答案,我必须这样做才能使其工作:
this.setTitle("my title!");
((TextView)v.findViewById(R.id.title)).setText(this.getTitle());
TextView title = ((TextView)v.findViewById(R.id.title));
title.setEllipsize(TextUtils.TruncateAt.MARQUEE);
title.setMarqueeRepeatLimit(1);
// in order to start strolling, it has to be focusable and focused
title.setFocusable(true);
title.setSingleLine(true);
title.setFocusableInTouchMode(true);
title.requestFocus();
这似乎有点矫枉过正 - 引用 v.findViewById(R.id.title)) 两次 - 但这是让我这样做的唯一方法。
【讨论】:
【参考方案17】:这是一个丑陋的黑客,但你可以这样做(因为 action_bar_title 是隐藏的):
try
Integer titleId = (Integer) Class.forName("com.android.internal.R$id")
.getField("action_bar_title").get(null);
TextView title = (TextView) getWindow().findViewById(titleId);
// check for null and manipulate the title as see fit
catch (Exception e)
Log.e(TAG, "Failed to obtain action bar title reference");
此代码适用于后 GINGERBREAD 设备,但也可以轻松扩展以与操作栏 Sherlock 一起使用
附:基于@pjv 评论,有更好的方法来查找操作栏标题 ID
final int titleId =
Resources.getSystem().getIdentifier("action_bar_title", "id", "android");
【讨论】:
我更喜欢 dtmilano 在***.com/questions/10779037/… 中的回答。它很相似,但更具未来性。 @pjv - 同意。似乎不那么“hacky”。我修改了答案 所以问题是关于自定义字体。这回答了如何获取默认操作栏的文本视图。 @kilaka - 想法是,如果您获得文本视图设置自定义字体将是微不足道的。虽然这是一篇旧帖子,但我认为 twaddington 的答案更受欢迎以上是关于如何在 ActionBar 标题中设置自定义字体?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ListView 和 AlertDialog 中设置自定义字体?
如何在 .xml 文件而不是 .java 文件中设置自定义字体?