41

I have a requirement to center a custom logo (using an ImageView) in the Actionbar for the "Home" activity. I'm using ABS for this project. This is very similar to a another question posted on S.O. (ActionBar logo centered and Action items on sides), but I'm not sure if the ImageView or search menu makes a difference, as I'm not getting the results I'm looking for (a centered image), or if I've just got it wrong. Basically, I set an Icon on the left, insert the custom view in the center, and have a search icon on the right (OptionsMenu). The image does appear a bit to the right of the icon, but it's still left of centered. Any pointers on how to center an ImageView in the actionbar would be greatly appreciated.

Home.java:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext()
            .getSystemService(LAYOUT_INFLATER_SERVICE);

    final View customActionBarView = inflater.inflate(
            R.layout.actionbar_custom_view_home, null);

    /* Show the custom action bar view and hide the normal Home icon and title */
    final ActionBar actionBar = getSupportActionBar();
    actionBar.setHomeButtonEnabled(true);
    actionBar.setDisplayHomeAsUpEnabled(false);
    actionBar.setDisplayShowTitleEnabled(false);
    actionBar.setIcon(R.drawable.ic_ab_som);
    actionBar.setCustomView(customActionBarView);
    actionBar.setDisplayShowCustomEnabled(true);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = new MenuInflater(this);
    inflater.inflate(R.menu.search, menu);
    return true;
}

res/layout/actionbar_custom_view_home.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:orientation="horizontal"
android:layout_gravity="center">

<ImageView
    android:id="@+id/actionBarLogo"
    android:contentDescription="@string/application_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:clickable="false"
    android:duplicateParentState="false"
    android:focusable="false"
    android:longClickable="false"
    android:padding="@dimen/padding_small"
    android:src="@drawable/logo_horizontal" />

</LinearLayout>

res/menu/search.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item 
        android:id="@id/search_item"
        android:icon="?attr/action_search"
        android:title="@string/search_label"
        android:showAsAction="ifRoom|collapseActionView">
    </item>
</menu>
Community
  • 1
  • 1
Doug Sparling
  • 535
  • 1
  • 5
  • 8
  • Please have a look at my question here: http://stackoverflow.com/questions/23783381/actionbar-with-custom-layout-does-not-occupy-full-screen-width-on-android-4-4-2 – Yash Sampat May 22 '14 at 07:45

8 Answers8

68

If you want imageview in Center of ActionBar then use:

enter image description here

just replace getActionBar(); to getSupportActionBar(); in below code

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ActionBar actionBar = getActionBar();
        actionBar.setCustomView(R.layout.actionbar_custom_view_home);
        actionBar.setDisplayShowTitleEnabled(false);
        actionBar.setDisplayShowCustomEnabled(true);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

your actionbar_custom_view_home.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:gravity="center"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/actionBarLogo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="false"
        android:focusable="false"
        android:longClickable="false"
        android:src="@drawable/ic_launcher" />

</LinearLayout>

Hide Actionbar Icon

enter image description here

final ActionBar actionBar = getActionBar();
actionBar.setCustomView(R.layout.actionbar_custom_view_home);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowCustomEnabled(true);
actionBar.setDisplayUseLogoEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);

Note: for < 11 API use getSupportActionBar() and > 11 API use getActionBar()


EDITED: 02/03/16 for Toolbar

<android.support.v7.widget.Toolbar
   style="@style/ToolBarStyle"
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:background="?attr/colorPrimary"
   android:minHeight="@dimen/abc_action_bar_default_height_material">

    <ImageView
        android:layout_width="wrap_content"
        android:contentDescription="@string/logo"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@drawable/ic_launcher"/>

 </android.support.v7.widget.Toolbar>
Dhaval Parmar
  • 18,812
  • 8
  • 82
  • 177
18

Explained:

enter image description here

The pink container, is the real space where you will add the view.

The trick is doing some maths, to center the View (whatever) to the middle.

In my case, the View was a TextView. Here's my full method:

public void addTextToActionBar( String textToSet )
{
    mActionbar.setDisplayShowCustomEnabled( true );

    // Inflate the custom view
    LayoutInflater inflater = LayoutInflater.from( this );
    View header = inflater.inflate( R.layout.actionbar_header, null );

    //Here do whatever you need to do with the view (set text if it's a textview or whatever)
    TextView tv = (TextView) header.findViewById( R.id.program_title );
    tv.setText( textToSet );

    // Magic happens to center it.
    int actionBarWidth = DeviceHelper.getDeviceWidth( this ); //Google for this method. Kinda easy.

    tv.measure( 0, 0 );
    int tvSize = tv.getMeasuredWidth();

    try
    {
        int leftSpace = 0;

        View homeButton = findViewById( android.R.id.home );
        final ViewGroup holder = (ViewGroup) homeButton.getParent();

        View firstChild =  holder.getChildAt( 0 );
        View secondChild =  holder.getChildAt( 1 );

        leftSpace = firstChild.getWidth()+secondChild.getWidth();
    }
    catch ( Exception ignored )
    {}

    mActionbar.setCustomView( header );

    if ( null != header )
    {
        ActionBar.LayoutParams params = (ActionBar.LayoutParams) header.getLayoutParams();

        if ( null != params )
        {
            int leftMargin =  ( actionBarWidth / 2 - ( leftSpace ) ) - ( tvSize / 2 ) ;

            params.leftMargin = 0 >= leftMargin ? 0 : leftMargin;
        }
    }
}

Layout:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal|center_vertical|center"
    android:orientation="horizontal" >

<TextView
    android:id="@+id/program_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@android:color/white"
    android:contentDescription="@string/content_description_program_title"
    android:ellipsize="end"
    android:maxLines="1"
    android:textSize="22sp"/>

</RelativeLayout>

Enjoy.

Reinherd
  • 5,476
  • 7
  • 51
  • 88
  • Can you add the code of your actionbar_header please? I´m having a Cast Exception on the ActionBar.LayoutParams line. Thanks! – reixa Jul 03 '14 at 08:34
  • Hello, I've edited the code, now you should provide a View and it should be added. I've also added the layout. – Reinherd Jul 03 '14 at 12:48
  • The xml layout it´s your actionbar_layout or your viewToAdd? – reixa Jul 04 '14 at 11:10
  • Wohoops i misswrote. The idea is that those both is the same view. – Reinherd Jul 04 '14 at 11:58
  • I´m getting a ClassCastException android.app.ActionBar$LayoutParams cannot be cast to android.support.v7.app.ActionBar$LayoutParams in ActionBar.LayoutParams params = (ActionBar.LayoutParams) header.getLayoutParams(); line. Any thoughts? Thanks in advance :) – reixa Jul 04 '14 at 12:15
  • Oh my code doesnt handle legacy actionbar (support library) – Reinherd Jul 04 '14 at 12:37
  • Ops! Thanks anyway ;) – reixa Jul 11 '14 at 12:11
  • What if i have a image at right and text at middle , How can i set this layout to ActionBar ? – ManishSB Nov 24 '14 at 11:38
  • Group those two items (I guess a `RelativeLayout` and add it instead of the `TextView` in the above code). Anyways check the new Toolbar, which can replace old ActionBar and centering items in the actionbar is preety much straight-forward: http://antonioleiva.com/material-design-everywhere/ – Reinherd Nov 24 '14 at 11:42
  • What is DeviceHelper? – e-info128 Apr 16 '15 at 15:05
  • A static helper class which holds some methods relating the device. In this case, with a method to get device width. – Reinherd Apr 16 '15 at 15:06
  • @SergiCastellsaguéMillán hey, I am unable to find android.R.id.home. It always returns null. Is there any trick to this? Cheers – Jakub Holovsky Jul 31 '15 at 07:45
  • @JakubHolovsky where are you using this code? It should be on the activity after setContentView – Reinherd Jul 31 '15 at 07:47
  • @SergiCastellsaguéMillán Hello Sergi, yep, calling it after setContentView. – Jakub Holovsky Jul 31 '15 at 08:25
  • 2
    @Jakub, I really recommend you to switch to Toolbar, which is a "raw" view instead of hacking the toolbar. It used to save my life before, until I switched to toolbar: http://antonioleiva.com/material-design-everywhere/ – Reinherd Jul 31 '15 at 08:28
  • @SergiCastellsaguéMillán actually, that is exactly what I thought as well. Cheers :) It was our next task to switch to toolbar so this might be a good excuse to wait with this until we do the switch. – Jakub Holovsky Jul 31 '15 at 09:07
  • How does this work at all? You say to call "after setContentView", but the layout may not have been calculated yet, so all View ".getWidth()" calls will return 0. – swooby Aug 25 '16 at 22:19
  • @swooby you're right, you could add a view tree observer listener and do it once layout pass is done – Reinherd Aug 29 '16 at 12:35
7

I encountered this problem,here is my solution:

ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(
        ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT);
layoutParams.gravity = Gravity.CENTER_HORIZONTAL|Gravity.CENTER_HORIZONTAL;
actionBar.setCustomView(yourCustomView,layoutParams);
jeason_tse
  • 71
  • 1
  • 1
3

The ImageView in your code is centered relative to the LinearLayout, not to the Action Bar. You can add left margin (android:layout_marginLeft) to the layout to adjust image position.

Other way to do it is not to add an icon and action items to the Action Bar, but to use a custom layout with icon and buttons inside. But you will need to handle action items yourself in that case.

Const
  • 976
  • 7
  • 11
3

Late to the party but in case it helps anyone else - use a layer-list and set it as the background. Otherwise, the logo will be centering based on remaining space, not the entire toolbar as Reinherd mentions.

You can use a layer-list with a static background color, and an image with gravity set to center as below. Hope it helps!

toolbar.axml

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="@drawable/toolbar_background"
    android:theme="@style/ThemeOverlay.AppCompat.Dark"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:layout_scrollFlags="scroll|enterAlways"
    app:layout_collapseMode="pin">
</android.support.v7.widget.Toolbar>

toolbar_background.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
    <shape android:shape="rectangle">
      <solid android:color="@color/colorPrimary" />
    </shape>
  </item>
  <item>
    <bitmap android:src="@drawable/logo" android:gravity="center" />
  </item>
</layer-list>
Blueberry
  • 2,211
  • 3
  • 19
  • 33
2

I'm faced with the same problem and I suggest the following solution:

  1. in your res/layout/actionbar_custom_view_home.xml change width of layout to wrap_content:

    android:layout_width="wrap_content"
    
  2. Get width of action bar like this:

    Display display = getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    //width of action bar is the same as width of whole screen
    final int actionBarWidth = size.x;
    
  3. Add layoutListener to your customActionBarView:

    customActionBarView.addOnLayoutChangeListener(
      new OnLayoutChangeListener() {
    
        @Override
        public void onGlobalLayout() {
          float x = customActionBarView.getX();
          int logoImageWidth = imageLogo.getWidth();
          int logoPosition = actionBarWidth / 2 - logoImageWidth / 2;
          if (x != logoPosition) {
            customActionBarView.setX(logoPosition);
            customActionBarView.requestLayout();
          } else {
            customActionBarView.removeOnLayoutChangeListener(this);
          }
        }
      }
    );
    
Alexey Osminin
  • 190
  • 1
  • 4
  • 14
2

The only thing I found working is putting (put right or left as needed, or both):

android:layout_marginLeft|Right="?attr/actionBarSize"

that I found here: http://sourcey.com/android-custom-centered-actionbar-with-material-design/

walla
  • 293
  • 1
  • 2
  • 16
0

For me "layoutParams.leftMargin" did the magic. I am able to push icon from left to right.

    androidx.appcompat.app.ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayOptions(actionBar.getDisplayOptions()
            | ActionBar.DISPLAY_SHOW_CUSTOM);
    actionBar.setDisplayOptions(actionBar.getDisplayOptions());
    ImageView imageView = new ImageView(actionBar.getThemedContext());
    imageView.setImageResource(R.drawable.content_copy);

    ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(
            ActionBar.LayoutParams.WRAP_CONTENT,
            ActionBar.LayoutParams.WRAP_CONTENT
            );
    layoutParams.leftMargin = 50;
    imageView.setLayoutParams(layoutParams);

    actionBar.setCustomView(imageView);
Bamdeb Ghosh
  • 134
  • 1
  • 9