在ActionBar选项卡标题中使用自定义字体

5
我正在尝试在我的ActionBar选项卡标题上设置自定义字体。
我看到更多的开发者在SO上询问如何正确地实现这个功能(例如如何自定义Action Bar标签的字体如果可能,我如何在选项卡文本中设置来自我的资产文件夹中的自定义字体?),但没有答案。
到目前为止,我已经尝试了两种方法:
1)第一种方法是受到这个SO问题的启发,它包括为每个选项卡填充一个自定义布局:
LayoutInflater inflater = LayoutInflater.from(this);
View customView = inflater.inflate(R.layout.tab_title, null); // a custom layout for the tab title, basically contains a textview...

TextView titleTV = (TextView) customView.findViewById(R.id.action_custom_title);
        titleTV.setText(mSectionsPagerAdapter.getPageTitle(i));
        titleTV.setGravity(Gravity.CENTER_VERTICAL);
        titleTV.setTypeface(((MyApp) getApplicationContext()).getCustomTypeface());

// ...Here I could also add any other styling I wanted to...

actionBar.getTabAt(i).setCustomView(customView);

这似乎不是一个很好的方法,因为如果选项卡和操作在横向模式下无法适应ActionBar,则选项卡标题将显示在溢出列表(Spinner / Drop-down)中,但所选值将显示为空。当您单击此列表项时,所有这些视图都会消失。例如,当用户扩展搜索操作视图时,会导致Android将选项卡显示为下拉菜单,这尤其令人讨厌。
2)我已经尝试了另一种方法,如here所示,其中涉及使用SpannableString,但字体没有更改为我的自定义字体。
SpannableString s = new SpannableString(mSectionsPagerAdapter.getPageTitle(i));
s.setSpan(new TypefaceSpan(this, "FontName.ttf"), 0, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
actionBar.addTab(actionBar.newTab().setText(s).setTabListener(this));

Class TypefaceSpan 可以在这里查看

所以...

有没有人知道如何使用来自“/assets/fonts/...”的 Typeface 来为 ActionBar 标签的标题设置样式?任何帮助将不胜感激。

编辑:

更多关于第二种方法的信息。我正在使用的 TypefaceSpan 类实际上是用户 @twaddington 在这里提供的 android.text.style.TypefaceSpan 的分支:如何在 ActionBar 标题中设置自定义字体?

编辑 2:

在之前的链接中,有一条评论提到:“如果在底层TextView上将textAllCaps属性设置为true(例如通过主题),则自定义字体将不会出现。当我将这种技术应用于操作栏选项卡项目时,这是一个问题”
我已经更改了我的样式,使textAllCaps设置为false,现在第二种方法似乎可行。我会进行一些测试并发布结果。 结论: 先前的解决方案似乎可行。
将@CommonsWare的答案标记为正确,因为它的相关性。 PS-针对@PeteH的编辑: 我6个月前问过这个问题,所以我不记得所有细节。我相信对于这个应用程序,我最终采取了不同的导航方法。现在我在应用程序中找到的所有内容(关于滑动的...)都是一个包含ViewPager和PagerTabStrip的Activity,我将其样式设置为:
// Style the Tab Strip:
Typeface tf = ((MyApplication) getApplication()).getTabStripTypeface(); // Used this to keep a single instance of the typeface (singleton pattern) and avoid mem. leaks
PagerTabStrip strip = (PagerTabStrip) findViewById(R.id.pager_title_strip);
strip.setTabIndicatorColor(getResources().getColor(R.color.myColor));
strip.setDrawFullUnderline(true);
for (int i = 0; i < strip.getChildCount(); ++i) {
    View nextChild = strip.getChildAt(i);
    if (nextChild instanceof TextView) {
        TextView textViewToConvert = (TextView) nextChild;
                    textViewToConvert.setAllCaps(false); 
        textViewToConvert.setTypeface(tf);
    }
}

虽然问题不同,但与此提问中所述的问题有关。

我能找到的唯一相关代码是这个,在这里我设置了一个SpannableString

// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
    SpannableString s = new SpannableString(mSectionsPagerAdapter.getPageTitle(i));
    s.setSpan(new TypefaceSpan(this, "FontName.ttf"), 0, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    actionBar.addTab(actionBar.newTab().setText(s).setTabListener(this));
}

...而我的styles.xml中,我将Actionbar的选项卡文本样式设置为这样:

<!-- action bar tabtext style -->
<style name="ActionBarTabText.MyApplication" parent="@android:style/Widget.Holo.ActionBar.TabText">
    <item name="android:textAppearance">@android:style/TextAppearance.Holo.Medium</item>
    <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
    <item name="android:textSize">15sp</item>
    <item name="android:textStyle">bold</item>
    <item name="android:textAllCaps">false</item>
    <item name="android:ellipsize">marquee</item>
    <item name="android:maxLines">1</item>
</style>

TEXTALLCAPS,很好的发现并感谢发布解决方案。 - Warpzit
2个回答

4

TypefaceSpan 仅适用于三种内置字体。

话虽如此,forking TypefaceSpan 进行修改,以使用从本地文件路径加载的 Typeface 并不难。而不是将构造函数中的 String 视为面部族名称,您应将其视为本地文件路径,并调整 apply() 以从该位置加载它。 Typeface 本身不是可 Parcelable 的,因此您需要使用路径来处理。

从资产获取 Typeface 的问题在于,TypefaceSpan 需要访问 AssetManager,并且在被放入 Parcel 中并重新构建后,它不会轻松地访问其中一个。

我没有使用您的第一种技术,但我并不惊讶您遇到了问题。

您还可以考虑完全放弃操作栏选项卡,并切换到带有选项卡指示器的 ViewPager,因为您可能更容易地对其进行样式设置,例如 Jake Wharton 的 TabPageIndicator


1
我已经在使用一个自定义的TypefaceSpan实现(已编辑的问题),它从资产中加载Typeface(基于用户@twaddington在此处显示的一些代码:https://gist.github.com/twaddington/b91341ea5615698b53b8)。 - user1987392
@user1987392:就个人而言,我认为他的实现有点令人不安,因为在操作栏标题最终以 Parcel 形式出现的情况下可能会出现问题。也许这种情况通常不会发生。无论如何,如果您正在使用他的代码,请从字体名称中删除 .ttf。他的实现附加了 .otf 并假定您的字体位于 assets/ 中的 fonts/ 中。如果您确实使用 .ttf 文件和/或您的字体位于 assets/ 的其他位置,则需要进一步调整他的代码。 - CommonsWare
我修改了他的代码,以便考虑到构造函数中提供的字体名称中的扩展名。在调试时,我可以看到Typeface对象已创建(否则程序将崩溃)。我也不太喜欢这种方法,开始倾向于使用建议的TabPageIndicator或尝试使用ActionBarSherlock,尽管我更喜欢坚持默认方法。 - user1987392
@CommonsWare 底层的 MetricAffectingSpan 不是可包裹对象。实现非常简单。只需加载字体,将其推入内存缓存并更新用于绘制文本的 TextPaint。这是所有正常框架 API 代码。如果您对如何改进它有建议,请给我发送电子邮件。我们已经在生产中使用这个代码将近一年了,没有任何问题。.ttf 的反馈是公平的,我已经更新了原始答案。 - twaddington
@user1987392:您能否提供一下实际有效的方法的代码?我按照您的顺序独立攻击了这个问题,但仍然无法找到一个可行的解决方案。(我承认看到我不是唯一一个在看似应该有两种可行方法的情况下失败的人,我感觉好多了。) - PeteH
@PeteH 请看PS-EDIT。希望能对您有所帮助。 - user1987392

0

首先看一下这个例子: [http://www.androidhive.info/2013/10/android-tab-layout-with-swipeable-views-1/][1]

然后创建一个名为tab_title的布局,使用以下代码:

<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/action_custom_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="My Custom title"
android:textColor="#fff"
android:textSize="18sp"
android:paddingTop="5dp" />

然后,在Androidhive项目的MainActivity的onCreate()方法中,只需更改:

 // Adding Tabs
    for (String tab_name : tabs) {
        actionBar.addTab(actionBar.newTab().setText(tab_name)
                .setTabListener(this));
    }

至:

// Adding Tabs
    for (String tab_name : tabs) {

        Tab tab = actionBar.newTab();
        TextView customTabView = (TextView)getLayoutInflater().inflate(R.layout.tab_title, null);
        customTabView.setText(tab_name);
        Typeface typface2=Typeface.createFromAsset(getAssets(),"fonts/titr.TTF");
        customTabView.setTypeface(typface2);            
        tab.setTabListener(this);           
        tab.setCustomView(customTabView);
        actionBar.addTab(tab);
    }

不需要说您必须将字体/titr.TTF更改为您的资产目录和文件名

联合起来吧!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接