如何在Android中使ActionBar标题居中对齐?

109

我试图使用以下代码将文本居中显示在ActionBar中,但它会左对齐。

如何使其居中显示?

ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle("Canteen Home");
actionBar.setHomeButtonEnabled(true);
actionBar.setIcon(R.drawable.back);

1
这是一个非常老的问题。然而,我下面看到的唯一解决方案是创建自定义操作栏。所以这里提供了不创建自定义操作栏的解决方案。http://stackoverflow.com/a/42465266/3866010 希望能帮助到某些人。 - ᴛʜᴇᴘᴀᴛᴇʟ
3
在我提出这个问题将近8年之后,现在再次使用答案 :D - Sourabh Saldi
18个回答

210

如果你想在ABS中实现标题居中(如果你想在默认的ActionBar中实现这个效果,只需在方法名称中删除“support”即可),可以尝试以下代码:

在你的Activity中,在onCreate()方法里添加以下代码:

getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 
getSupportActionBar().setCustomView(R.layout.abs_layout);

abs_layout:

维护一个绝对布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
        android:layout_gravity="center"
    android:orientation="vertical">

    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/tvTitle"
        style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textColor="#FFFFFF" />

</LinearLayout>

现在你应该已经拥有一个仅带标题的 Actionbar。如果你想设置自定义背景,请在上面的布局中设置它(但是不要忘记设置 android:layout_height="match_parent")。

或者使用以下方式:

getSupportActionBar().setBackgroundDrawable(getResources().getDrawable(R.drawable.yourimage));

7
如何添加自定义返回按钮图像? - Sourabh Saldi
13
对我来说,结果是操作栏有些向右或向左偏移,具体取决于我显示的操作按钮。为了修复它,我只需将layout_width设置为 "WRAP_CONTENT"即可。 - alfongj
12
Pepillo的解决方案对我没有用,因为内容不再居中。我通过在LinearLayout中添加“android:layout_gravity =“center””来解决这个问题。 - Tom Naessens
8
这是一种预期行为。请尝试使用以下代码:((TextView)actionBar.getCustomView().findViewById(R.id.textView1)).setText("新标题"); 其中textView1是您自定义视图中TextView的ID。请注意不要改变原本的意思。 - Sufian
8
如果有菜单项,标题就无法居中显示。为了确保标题始终居中,需要在LinearLayout中添加"WRAP_CONTENT",并将android:layout_gravity="center"从TextView移动到LinearLayout。 - DominicM
显示剩余14条评论

36

其他答案对我来说没有太大的帮助...下面是在Android 4.4.3上使用support库v7中的ActionBar时对我有效的解决方案。我已经设置好了导航抽屉图标(“汉堡菜单按钮”)

XML

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/actionbar_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:maxLines="1"
        android:clickable="false"
        android:focusable="false"
        android:longClickable="false"
        android:textStyle="bold"
        android:textSize="18sp"
        android:textColor="#FFFFFF" />

</LinearLayout>

Java

//Customize the ActionBar
final ActionBar abar = getSupportActionBar();
abar.setBackgroundDrawable(getResources().getDrawable(R.drawable.actionbar_background));//line under the action bar
View viewActionBar = getLayoutInflater().inflate(R.layout.actionbar_titletext_layout, null);
ActionBar.LayoutParams params = new ActionBar.LayoutParams(//Center the textview in the ActionBar !
        ActionBar.LayoutParams.WRAP_CONTENT, 
        ActionBar.LayoutParams.MATCH_PARENT, 
        Gravity.CENTER);
TextView textviewTitle = (TextView) viewActionBar.findViewById(R.id.actionbar_textview);
textviewTitle.setText("Test");
abar.setCustomView(viewActionBar, params);
abar.setDisplayShowCustomEnabled(true);
abar.setDisplayShowTitleEnabled(false);
abar.setDisplayHomeAsUpEnabled(true);
abar.setIcon(R.color.transparent);
abar.setHomeButtonEnabled(true);

为什么我们需要创建一个 params 对象?难道我们不能在分配给 ActionBar 的外部布局文件中指定重力吗? - Deep Lathia

10

按照Sergii所说的方法,定义一个带标题文本的自定义视图,然后传递LayoutParams给setCustomView()。

ActionBar actionBar = getSupportActionBar()
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 
actionBar.setCustomView(getLayoutInflater().inflate(R.layout.action_bar_home, null),
        new ActionBar.LayoutParams(
                ActionBar.LayoutParams.WRAP_CONTENT,
                ActionBar.LayoutParams.MATCH_PARENT,
                Gravity.CENTER
        )
);

编辑:至少对于宽度,你应该使用WRAP_CONTENT或者你的导航抽屉、应用图标等不会被显示(自定义视图显示在操作栏的其他视图之上)。这种情况尤其会发生在没有显示任何动作按钮时。

编辑:XML布局中的等效方法:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="center_horizontal"
    android:orientation="vertical">

这不需要指定LayoutParams。

actionBar.setCustomView(getLayoutInflater().inflate(R.layout.action_bar_home, null);

只有使用Params才能使标题居中,没有Params的话,标题就不会居中。 - undefined

9

仅做一个补充,关于Ahmad的回答。当使用自定义视图和TextView时,您不能再使用getSupportActionBar().setTitle来设置标题。因此,在具有此自定义操作栏(使用此xml)的多个Activities中设置标题时,在onCreate()方法中,分配自定义视图之后:

TextView textViewTitle = (TextView) findViewById(R.id.mytext);
textViewTitle.setText(R.string.title_for_this_activity);

7

这里的代码与我的工作相关。

    // Activity 
 public void setTitle(String title){
    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    TextView textView = new TextView(this);
    textView.setText(title);
    textView.setTextSize(20);
    textView.setTypeface(null, Typeface.BOLD);
    textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
    textView.setGravity(Gravity.CENTER);
    textView.setTextColor(getResources().getColor(R.color.white));
    getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
    getSupportActionBar().setCustomView(textView);
} 

// Fragment
public void setTitle(String title){
    ((AppCompatActivity)getActivity()).getSupportActionBar().setHomeButtonEnabled(true);
    ((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    TextView textView = new TextView(getActivity());
    textView.setText(title);
    textView.setTextSize(20);
    textView.setTypeface(null, Typeface.BOLD);
    textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
    textView.setGravity(Gravity.CENTER);
    textView.setTextColor(getResources().getColor(R.color.white));
    ((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
    ((AppCompatActivity)getActivity()).getSupportActionBar().setCustomView(textView);
}

4

好的。经过大量研究,结合上面所接受的答案,我提出了一个解决方案,即使您的操作栏中还有其他内容(返回/主页按钮、菜单按钮),也可以使用此解决方案。因此,我将重写方法放在了基本活动中(所有其他活动都扩展了它),并在那里放置了代码。此代码将每个活动的标题设置为AndroidManifest.xml中提供的标题,并执行其他一些自定义操作(例如在操作栏按钮上设置自定义颜色和在标题上设置自定义字体)。您只需要在action_bar.xml中省略重力,并改用填充即可。actionBar != null检查被使用,因为并非所有我的活动都有操作栏。

在4.4.2和5.0.1上测试通过。

public class BaseActivity extends AppCompatActivity {
private ActionBar actionBar;
private TextView actionBarTitle;
private Toolbar toolbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    super.onCreate(savedInstanceState);     
    ...
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

    actionBar = getSupportActionBar();
    if (actionBar != null) {
        actionBar.setElevation(0);
        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
        actionBar.setCustomView(R.layout.action_bar);

        LinearLayout layout = (LinearLayout) actionBar.getCustomView();
        actionBarTitle = (TextView) layout.getChildAt(0);
        actionBarTitle.setText(this.getTitle());
        actionBarTitle.setTypeface(Utility.getSecondaryFont(this));
        toolbar = (Toolbar) layout.getParent();
        toolbar.setContentInsetsAbsolute(0, 0);

        if (this.getClass() == BackButtonActivity.class || this.getClass() == AnotherBackButtonActivity.class) {
            actionBar.setHomeButtonEnabled(true);
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setDisplayShowHomeEnabled(true);
            Drawable wrapDrawable = DrawableCompat.wrap(getResources().getDrawable(R.drawable.ic_back));
            DrawableCompat.setTint(wrapDrawable, getResources().getColor(android.R.color.white));
            actionBar.setHomeAsUpIndicator(wrapDrawable);
            actionBar.setIcon(null);
        }
        else {
            actionBar.setHomeButtonEnabled(false);
            actionBar.setDisplayHomeAsUpEnabled(false);
            actionBar.setDisplayShowHomeEnabled(false);
            actionBar.setHomeAsUpIndicator(null);
            actionBar.setIcon(null);
        }
    }

    try {
        ViewConfiguration config = ViewConfiguration.get(this);
        Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
        if(menuKeyField != null) {
            menuKeyField.setAccessible(true);
            menuKeyField.setBoolean(config, false);
        }
    } catch (Exception ex) {
        // Ignore
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (actionBar != null) {
        int padding = (getDisplayWidth() - actionBarTitle.getWidth())/2;

        MenuInflater inflater = getMenuInflater();
        if (this.getClass() == MenuActivity.class) {
            inflater.inflate(R.menu.activity_close_menu, menu);
        }
        else {
            inflater.inflate(R.menu.activity_open_menu, menu);
        }

        MenuItem item = menu.findItem(R.id.main_menu);
        Drawable icon = item.getIcon();
        icon.mutate().mutate().setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_IN);
        item.setIcon(icon);

        ImageButton imageButton;
        for (int i =0; i < toolbar.getChildCount(); i++) {
            if (toolbar.getChildAt(i).getClass() == ImageButton.class) {
                imageButton = (ImageButton) toolbar.getChildAt(i);
                padding -= imageButton.getWidth();
                break;
            }
        }

        actionBarTitle.setPadding(padding, 0, 0, 0);
    }

    return super.onCreateOptionsMenu(menu);
} ...

我的action_bar.xml文件如下(如果有人感兴趣):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:orientation="horizontal">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/actionbar_text_color"
        android:textAllCaps="true"
        android:textSize="9pt"
        />

</LinearLayout>

编辑:如果您需要在活动加载后更改标题名称为其他内容(onCreateOptionsMenu已经被调用),请将另一个TextView放入您的action_bar.xml中,并使用以下代码来“填充”这个新的TextView,设置文本并显示它:

protected void setSubTitle(CharSequence title) {

    if (!initActionBarTitle()) return;

    if (actionBarSubTitle != null) {
        if (title != null || title.length() > 0) {
            actionBarSubTitle.setText(title);
            setActionBarSubTitlePadding();
        }
    }
}

private void setActionBarSubTitlePadding() {
    if (actionBarSubTitlePaddingSet) return;
    ViewTreeObserver vto = layout.getViewTreeObserver();
    if(vto.isAlive()){
        vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int padding = (getDisplayWidth() - actionBarSubTitle.getWidth())/2;

                ImageButton imageButton;
                for (int i = 0; i < toolbar.getChildCount(); i++) {
                    if (toolbar.getChildAt(i).getClass() == ImageButton.class) {
                        imageButton = (ImageButton) toolbar.getChildAt(i);
                        padding -= imageButton.getWidth();
                        break;
                    }
                }

                actionBarSubTitle.setPadding(padding, 0, 0, 0);
                actionBarSubTitlePaddingSet = true;
                ViewTreeObserver obs = layout.getViewTreeObserver();
                obs.removeOnGlobalLayoutListener(this);
            }
        });
    }
}

protected void hideActionBarTitle() {

    if (!initActionBarTitle()) return;

    actionBarTitle.setVisibility(View.GONE);
    if (actionBarSubTitle != null) {
        actionBarSubTitle.setVisibility(View.VISIBLE);
    }
}

protected void showActionBarTitle() {

    if (!initActionBarTitle()) return;

    actionBarTitle.setVisibility(View.VISIBLE);
    if (actionBarSubTitle != null) {
        actionBarSubTitle.setVisibility(View.GONE);
    }
}
EDIT (25.08.2016): 如果你的活动具有“后退按钮”,则此方法不适用于appcompat 24.2.0版(2016年8月)。我已经提交了一个错误报告(Issue 220899),但我不知道它是否有任何用处(我怀疑它不会很快被修复)。与此同时,解决方案是检查子类是否等于AppCompatImageButton.class,并进行相同操作,只需将宽度增加30%(例如,在从原始填充值中减去该值之前,appCompatImageButton.getWidth()*1.3):
padding -= appCompatImageButton.getWidth()*1.3;

同时,我在其中加入了一些填充/边距检查:
Class<?> c;
ImageButton imageButton;
AppCompatImageButton appCompatImageButton;
for (int i = 0; i < toolbar.getChildCount(); i++) {
    c = toolbar.getChildAt(i).getClass();
    if (c == AppCompatImageButton.class) {
        appCompatImageButton = (AppCompatImageButton) toolbar.getChildAt(i);
        padding -= appCompatImageButton.getWidth()*1.3;
        padding -= appCompatImageButton.getPaddingLeft();
        padding -= appCompatImageButton.getPaddingRight();
        if (appCompatImageButton.getLayoutParams().getClass() == LinearLayout.LayoutParams.class) {
            padding -= ((LinearLayout.LayoutParams) appCompatImageButton.getLayoutParams()).getMarginEnd();
            padding -= ((LinearLayout.LayoutParams) appCompatImageButton.getLayoutParams()).getMarginStart();
        }
        break;
    }
    else if (c == ImageButton.class) {
        imageButton = (ImageButton) toolbar.getChildAt(i);
        padding -= imageButton.getWidth();
        padding -= imageButton.getPaddingLeft();
        padding -= imageButton.getPaddingRight();
        if (imageButton.getLayoutParams().getClass() == LinearLayout.LayoutParams.class) {
            padding -= ((LinearLayout.LayoutParams) imageButton.getLayoutParams()).getMarginEnd();
            padding -= ((LinearLayout.LayoutParams) imageButton.getLayoutParams()).getMarginStart();
        }
        break;
    }
}

4
经过大量研究,这确实有效:

getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
getActionBar().setCustomView(R.layout.custom_actionbar);
 ActionBar.LayoutParams p = new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
       p.gravity = Gravity.CENTER;

您需要定义自定义的custom_actionbar.xml布局,以满足您的要求,例如:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#2e2e2e"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_gravity="center">

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/top_banner"
        android:layout_gravity="center"
        />
</LinearLayout>

1
简单而有效! http://www.quotehd.com/imagequotes/authors39/tmb/clay-ogden-quote-hes-a-legend-he-deserves-respect.jpg - AndrewBramwell
@AndrewBramwell getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 抛出了空指针异常。 - Ruchir Baronia
你们知道我怎么能解决这个问题吗? - Ruchir Baronia

4
没有使用自定义视图,也可以将ActionBar标题居中。对于导航抽屉也完美适用。
int titleId = getResources().getIdentifier("action_bar_title", "id", "android");
TextView abTitle = (TextView) findViewById(titleId);
abTitle.setTextColor(getResources().getColor(R.color.white));

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

abTitle.setGravity(Gravity.CENTER);
abTitle.setWidth(metrics.widthPixels);
getActionBar().setTitle("I am center now");

3

它的功能非常好。

activity = (AppCompatActivity) getActivity();

activity.getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);

LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.custom_actionbar, null);

ActionBar.LayoutParams p = new ActionBar.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT,
        Gravity.CENTER);

((TextView) v.findViewById(R.id.title)).setText(FRAGMENT_TITLE);

activity.getSupportActionBar().setCustomView(v, p);
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);

以下是custom_actionbar的布局:

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

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:text="Example"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:ellipsize="end"
        android:maxLines="1"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="@color/colorBlack" />

</RelativeLayout>

3
一个纯Kotlin解决方案,不需要对XML布局进行更改:
//Function to call in onResume() of your activity
private fun centerToolbarText() {
    val mTitleTextView = AppCompatTextView(this)
    mTitleTextView.text = title
    mTitleTextView.setSingleLine()//Remove it if you want to allow multiple lines in the toolbar
    mTitleTextView.textSize = 25f
    val layoutParams = android.support.v7.app.ActionBar.LayoutParams(
        ActionBar.LayoutParams.WRAP_CONTENT,
        ActionBar.LayoutParams.WRAP_CONTENT
    )
    layoutParams.gravity = Gravity.CENTER
    supportActionBar?.setCustomView(mTitleTextView,layoutParams)
    supportActionBar?.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM
}


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