70

Using the last android.support.v7.widget.Toolbar I want to center an image in the toolbar but it keeps staying on the left.

The best way for me would be to use toolbar.setLogo() method and to center the logo but i don't see any way to do it.

I use a layout for the 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">

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

Is there any possibility to add an image (logo) to the toolbar and center it? programatically or in the layout?

Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
Nicolas Hauzaree
  • 743
  • 1
  • 5
  • 9

8 Answers8

142

Toolbar is just a ViewGroup, you can customize is as much as you want.

Try this :

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

This should bring your imageView in center of toolbar.

Abhinav Puri
  • 4,254
  • 1
  • 16
  • 28
  • How to change set icon grammatically ? please help. – Anand Savjani Jul 02 '15 at 09:50
  • @AnandSavjani What I did was set an ID on ImageView and then in my Activity I assign an ImageView variable to it. Then simply, toolbarID.SetImageResource(Resource.Drawable.logo); – MikeOscarEcho Jul 16 '15 at 18:36
  • 15
    As I see, Toolbar is extending ViewGroup, so `android:layout_gravity` is not valid attribute. Maybe I'm doing something wrong, but it's not working. – Goltsev Eugene Aug 30 '16 at 14:40
  • 1
    I have added `layout_width="match_parent"` attribute to `ImageView` and it works. – Wojtek Aug 13 '18 at 17:29
35

If you have any views and can't quite get the logo centered, it will be because the centering is based on remaining space, not the entire toolbar.

To guarantee the logo being centered, try using a layer-list as a background of your toolbar instead of trying to use an image as a view.

toolbar.xml

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

That should ensure a centered logo, with a specific background colour.

Moinkhan
  • 12,732
  • 5
  • 48
  • 65
Blueberry
  • 2,211
  • 3
  • 19
  • 33
  • 2
    this is a much better answer – Rony Tesler Mar 17 '16 at 00:27
  • 7
    How do you adjust size here with the drawable? – Lion789 Mar 22 '16 at 05:02
  • I noticed you had a comment on another question, so I assume you haven't found an answer - If you cant find another solution, maybe recreating the image with a particular size is your best bet. – Blueberry Mar 23 '16 at 15:40
  • 1
    Is there any way to adjust the size of the `bitmap`, because when I do this it makes the image i'm trying to use very huge and unusable within the `Toolbar`... – Sakiboy Nov 30 '16 at 18:27
9

This is not the best solution but it's a work around that works even when you have up button or menu item.

try

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

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

</FrameLayout>
Rubin Yoo
  • 2,674
  • 2
  • 24
  • 32
  • Nice answer - simple to follow. I've updated it for 2018 with a few enhancements [in my own answer](https://stackoverflow.com/a/53373773/383414) - if you want to copy those changes into yours I'd be happy to remove mine as it would no longer add anything useful. – Richard Le Mesurier Nov 19 '18 at 11:35
6

I like the approach given by Ruben Yoo's answer because of its simplicity. It is explicit, easy to follow, and keeps all the code changes together.

Here's an updated version with some minor improvements:

<android.support.design.widget.AppBarLayout
    android:id="@+id/layout_app_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize">
        </android.support.v7.widget.Toolbar>

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:contentDescription="@string/app_name"
            android:scaleType="centerInside"
            android:src="@mipmap/ic_launcher"/>
    </FrameLayout>

</android.support.design.widget.AppBarLayout>

Changes:

  1. introduced AppBarLayout parent
  2. explicit size ?attr/actionBarSize provided to frame & toolbar
  3. ImageView matches parent dimensions in width & height
  4. logo resized to centerInside
Richard Le Mesurier
  • 29,432
  • 22
  • 140
  • 255
2

I had a similar problem. I tried to use the layer-list approach that Blueberry suggested, but once I put in a high-res asset for the logo the solution no longer worked. A bitmap in a layer-list has a bug: It will enlarge smaller images to fit the space but won't shrink larger images. So, as long as you are okay with using tiny images that look grainy/pixelated when they are enlarged, layer-list works fine.

To solve this problem and to have a centered high-res logo, I completely removed the android:background attribute from Toolbar, added android:background="?attr/colorPrimary" to my AppBarLayout parent and then tossed this terrible code into my Activity's onCreate method:

    final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    ActionBar ab = getSupportActionBar();
    if (ab != null && toolbar != null)
    {
        // Hide the title text.
        ab.setDisplayShowTitleEnabled(false);

        // Convert and show the logo.
        toolbar.addOnLayoutChangeListener(new View.OnLayoutChangeListener()
        {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
            {
                ActionBar ab = getSupportActionBar();
                if (ab != null)
                {
                    Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.logo);
                    Bitmap bmp2 = Bitmap.createBitmap(toolbar.getWidth(), toolbar.getHeight(), bmp.getConfig());
                    Bitmap bmp3 = Bitmap.createScaledBitmap(bmp, bmp.getWidth() * toolbar.getHeight() / bmp.getHeight(), toolbar.getHeight(), true);
                    Canvas canvas = new Canvas(bmp2);
                    canvas.drawBitmap(bmp3, (toolbar.getWidth() / 2) - (bmp3.getWidth() / 2), 0, null);
                    BitmapDrawable background = new BitmapDrawable(getResources(), bmp2);
                    ab.setBackgroundDrawable(background);
                }
            }
        });
    }

It works by creating a canvas the size of the toolbar and a ratio-scaled version of the logo, drawing the newly resized logo onto the canvas in the center, and finally setting the bitmap being drawn on as the background of the action bar.

On the plus side, this approach gives you total control over placement, sizing, etc. Not limited to whatever you can do in XML. It's terrible because it is called pretty regularly whenever the toolbar layout changes, which means there are performance implications. But, when you are required by your design team (that cares not about the first thing regarding Material Design) to have a background logo and waste five hours looking for the solution above, performance stops mattering - you just want the damn thing to work. The above code reeks pretty badly of desperation.

I'll let someone more capable than me in Android development point out that "I'm doing it wrong" and fix whatever performance issues/bugs there are with the above code. It doesn't change the fact that layer-list bitmap is broken and this is a hack (that should not exist) to fix a stupid bug (that should also not exist) in Android.

maddog
  • 520
  • 4
  • 10
  • In my mind the best way would be the XML approach, with several sizes of the image for scaling. It is a fairly standard android approach. Not sure if I have encountered the same issue? – Blueberry Jun 23 '16 at 10:09
  • Devices come in all shapes and sizes so there is no way to handle every device unless you want to deliver a 200MB binary just for a logo. – maddog Jun 23 '16 at 22:01
  • I think all you should worry about is densities, of which there are only six you need to handle. Please see here for further information on how to support multiple densities. https://developer.android.com/guide/practices/screens_support.html#overview – Blueberry Jun 24 '16 at 00:29
  • Or I can use a single resource and the above code because layer-list bitmap should be intelligent enough to take a high-res image and scale it smaller, minding the image ratio. Sorry, but I'm not going back to revisit this. Native mobile app development should be easier. This was a pointless waste of my time. – maddog Jun 24 '16 at 18:21
  • Fair enough :). Just letting you know best practice but of course each project is different. – Blueberry Jun 24 '16 at 18:34
  • works for me. is there a better way to add some margin, or padding to the image. What I do now is Bitmap bmp3 = Bitmap.createScaledBitmap(bmp, (bmp.getWidth() * toolbar.getHeight() / bmp.getHeight()) - 10, toolbar.getHeight() - 10, true); (if I want a 10...) but not sure if it's a good aproach – OWADVL Feb 05 '18 at 16:22
1

If user set :

activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true); activity.getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_iconmenu);

and after do something like

<Toolbar ... >
   <ImageView ...>
   </ImageView>
</Toolbar>

then image inside toolbar will not be centered as well cause home button eat some space from layout.Image's horizontal center will be biased on home icon width.So best solution:
1.Create 9-patch png from your original image .png resource.
2.Create drawable from 9-patch with xml using layer-list as example toolbar_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@color/white"/><!-- fill color under image(optional) -->
    <item>
        <nine-patch
        android:src="@drawable/toolbar_image" />
    </item>
</layer-list>


Then set toolbar_background resource as background at Toolbar element:

<Toolbar android:background="toolbar_background" ...>
</Toolbar>


That's all.

0

If you need to center a more complicated layout in the Toolbar than just an image, this is what I placed to my Activity's onCreate():

mToolbar.addOnLayoutChangeListener(
            new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
                    // Push layout to the center
                    int toolbarCenterX = (int) (mToolbar.getWidth() / 2.0 - mMiddleToolbarLayout.getWidth() / 2.0));
                    if(mMiddleToolbarLayout.getX() != toolbarCenterX) {
                        mMiddleToolbarLayout.setX(toolbarCenterX);
                    }
                }
            }
    );

When onLayoutChange is called, your layout's width is already determined so you just push it to the center.

NOTE: It is important to only center toolbar (see the if condition) when it is not centered, otherwise this callback would be re-called in an infinite loop.

The XML file will look like this:

<android.support.v7.widget.Toolbar
...
>
    <LinearLayout
        android:id="@+id/middle_toolbar_layout"
        ...
    >
</android.support.v7.widget.Toolbar>
johnny
  • 169
  • 1
  • 8
0

you can use this code:

     <android.support.v7.widget.Toolbar

        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"

        android:background="?attr/colorPrimary"

        app:popupTheme="@style/AppTheme.PopupOverlay">


        <ImageView
            android:layout_width="250dp"
            android:layout_height="match_parent"
            android:src="@drawable/apptitle"/>
Matin Gdz
  • 217
  • 2
  • 13