OK After a lot of research, combined with the accepted answer above, I came up with a solution that also works if you have other things in the action bar (back / home button, menu button). So basically I put the override methods in the main action (which applies to all other actions) and put the code there. This code sets the title for each activity, as presented in AndroidManifest.xml, and also makes some other custom elements (for example, customize the hue on the buttons on the action bar and its own font in the title). You only need to leave gravity in the action_bar.xml file and use a pad instead. actionBar != null used since not all my actions have one.
Tested on 4.4.2 and 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) {
And my action_bar.xml looks like this (if anyone is interested):
<?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>
EDIT . If you need to change the title to something else. AFTER loading the activity (onCreateOptionsMenu has already been called), add another TextView to your action_bar.xml file and use the following code to “pad” this new TextView, set the text and show it:
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 (08/25/2016) . This does not work with appcompat version 24.2.0 (August 2016) if there is a back button in your activity. I published a bug report ( Issue 220899 ), but I don’t know if it will be used (doubt that it will be fixed soon). Meanwhile, the solution is to check if the child class is equal to the AppCompatImageButton class. class and do the same, only increase the width by 30% (for example, appCompatImageButton.getWidth () * 1.3, before subtracting this value from the original addition):
padding -= appCompatImageButton.getWidth()*1.3;
At the same time, I threw some fill / field checks:
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; } }