Toolbar image centered
AndroidAndroid ToolbarAndroid Problem Overview
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?
Android Solutions
Solution 1 - Android
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.
Solution 2 - Android
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.
Solution 3 - Android
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>
Solution 4 - Android
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:
- introduced
AppBarLayout
parent - explicit size
?attr/actionBarSize
provided to frame & toolbar ImageView
matches parent dimensions in width & height- logo resized to
centerInside
Solution 5 - Android
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.
Solution 6 - Android
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.
Solution 7 - Android
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>
Solution 8 - Android
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"/>