如何在动作栏标题中设置自定义字体?

如何(如果可能的话)我可以设置自定义字体在ActionBar标题文本(只有-不是标签文本)与字体在我的资产文件夹?我不想使用android:logo选项。

155383 次浏览

我同意这不是完全支持的,但以下是我所做的。您可以为操作栏使用自定义视图(它将显示在图标和操作项之间)。我正在使用一个自定义视图,我已经禁用了本机标题。我所有的活动都继承自一个活动,它在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);

我的layout xml (R.layout。标题视图在上面的代码)看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent" >


<com.your.package.CustomTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:textSize="20dp"
android:maxLines="1"
android:ellipsize="end"
android:text="" />
</RelativeLayout>

这是一个丑陋的黑客,但你可以这样做(因为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");
}

这段代码适用于后姜饼设备,但也可以很容易地扩展到动作栏Sherlock

附注:基于@pjv评论,有一个更好的方法找到操作栏标题id

final int titleId =
Resources.getSystem().getIdentifier("action_bar_title", "id", "android");

你可以使用自定义的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类被传递给你的Activity上下文和你的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方法中实现它,如上所示。

为了补充@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))——但这是它允许我这样做的唯一方式。

int titleId = getResources().getIdentifier("action_bar_title", "id",
"android");
TextView yourTextView = (TextView) findViewById(titleId);
yourTextView.setTextColor(getResources().getColor(R.color.black));
yourTextView.setTypeface(face);

以下代码将适用于所有版本。我确实在gingerbread设备和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);
}
}

书法库允许您通过应用程序主题设置自定义字体,这也适用于操作栏。

<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>

激活书法所需要的是将它附加到你的活动上下文:

@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(new CalligraphyContextWrapper(newBase));
}

默认的自定义属性是fontPath,但是你可以通过在你的Application类中使用CalligraphyConfig.Builder初始化它来为路径提供你自己的自定义属性。不鼓励使用android:fontFamily

如果你想在整个活动中设置所有textview的字体,你可以使用这样的东西:

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);
}

TypefaceCache:

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));
}
}

使用新的工具栏在支持库设计你自己的动作栏或使用下面的代码

膨胀的Textview不是一个好的选择,尝试可扩展的字符串生成器

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);
}


}

试试这个

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);
}

我们需要使用反射来实现这一点

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) {
}
}

更新正确答案。

首先:将标题设置为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_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent" >


<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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
}

下载字体文件:因为我把文件存储到cloudinary,所以我有链接下载它。

/**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;
}
}
}
}

我只是在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"中使用你新添加的字体

Android支持库v26 + Android Studio 3.0开始,这个过程变得简单极了!!

按照以下步骤更改工具栏标题的字体:

  1. 读取可下载的字体 &从列表中选择任意字体(我的建议)或根据XML字体将自定义字体加载到res > font
  2. 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>
    
  3. Insert a new line in your Toolbar properties app:titleTextAppearance="@style/TextAppearance.TabsFont" as shown below

    <android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:titleTextAppearance="@style/TitleBarTextAppearance"
    app:popupTheme="@style/AppTheme.PopupOverlay"/>
    
  4. Enjoy Custom Actionbar Title font styling!!

    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);

没有自定义的文本视图是必需的!

首先,在你的java代码中禁用toobar中的标题: getSupportActionBar () .setDisplayShowTitleEnabled(假);< / p >

然后,只需在工具栏内添加一个TextView:

<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textSize="18sp"
android:fontFamily="@font/roboto" />


</android.support.v7.widget.Toolbar>

试试这个

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);