26

I want to remove the padding around the icon on the left in the standard android 4.0+ action bar. I'm setting the icon with:

getActionBar().setIcon(getResources().getDrawable(R.drawable.ic_action_myapp));

And I would like the icon to fill vertically the space, touching both top and bottom, similar to what soundcloud app does:

luca
  • 12,311
  • 15
  • 70
  • 103

6 Answers6

29

Digging into AOSP sources, it seems the code involved is in com.android.internal.widget.ActionBarView.java. In particular the relevant part is the onLayout() method of the inner class ActionBarView$HomeView, partially reported below (lines 1433-1478):

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        ...
        final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
        final int iconHeight = mIconView.getMeasuredHeight();
        final int iconWidth = mIconView.getMeasuredWidth();
        final int hCenter = (r - l) / 2;
        final int iconTop = Math.max(iconLp.topMargin, vCenter - iconHeight / 2);
        final int iconBottom = iconTop + iconHeight;
        final int iconLeft;
        final int iconRight;
        int marginStart = iconLp.getMarginStart();
        final int delta = Math.max(marginStart, hCenter - iconWidth / 2);
        if (isLayoutRtl) {
            iconRight = width - upOffset - delta;
            iconLeft = iconRight - iconWidth;
        } else {
            iconLeft = upOffset + delta;
            iconRight = iconLeft + iconWidth;
        }
        mIconView.layout(iconLeft, iconTop, iconRight, iconBottom);
    }

the same widget use this layout, defined in res/layout/action_bar_home.xml:

<view xmlns:android="http://schemas.android.com/apk/res/android"
  class="com.android.internal.widget.ActionBarView$HomeView"
  android:layout_width="wrap_content"
  android:layout_height="match_parent">
<ImageView android:id="@android:id/up"
           android:src="?android:attr/homeAsUpIndicator"
           android:layout_gravity="center_vertical|start"
           android:visibility="gone"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginEnd="-8dip" />
<ImageView android:id="@android:id/home"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginEnd="8dip"
           android:layout_marginTop="@android:dimen/action_bar_icon_vertical_padding"
           android:layout_marginBottom="@android:dimen/action_bar_icon_vertical_padding"
           android:layout_gravity="center"
           android:adjustViewBounds="true"
           android:scaleType="fitCenter" />
</view>

According to sources the icon is shown in the Imageview with id=android.R.id.home. The onLayout() method reported above takes account of the ImageView margins defined in the layout, which can't be set via theme/style override because they use the value @android:dimen/action_bar_icon_vertical_padding.

All you can do is to get rid of those values at runtime, and set them according your needs: simply retrieve the ImageView and set its top and bottom margins to 0. Something like this:

ImageView icon = (ImageView) findViewById(android.R.id.home);
FrameLayout.LayoutParams iconLp = (FrameLayout.LayoutParams) icon.getLayoutParams();
iconLp.topMargin = iconLp.bottomMargin = 0;
icon.setLayoutParams( iconLp );

EDIT: I've just realized I didn't cover how to get rid of left padding. Solution below.

Left padding on actionbar is affected by the Navigating Up behavior of actionbar icon. When that is disabled (via ActionBar.setDisplayHomeAsUpEnabled(false)) the left/up indicator is gone, but a left padding is used as well. A simple solution:

  1. enable the actionbar up navigation using ActionBar.setDisplayHomeAsUpEnabled(true) in order to consider the indicator view in the layout process
  2. force the drawable used as up indicator in your res/values-v14/styles.xml to null

eg:

<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
    <!-- API 14 theme customizations can go here. -->
    <item name="android:homeAsUpIndicator">@null</item>
</style>
a.bertucci
  • 12,142
  • 2
  • 31
  • 32
  • 1
    I didn't try yet, but it seems reasonable and well written so you get the bounty.. I'll mark as accepted as soon as I have time to try it ;-) – luca Apr 29 '13 at 03:24
  • Thanks @luca ;) I tested the code myself before posting here, so I'm confident it will work for you as well. – a.bertucci Apr 29 '13 at 11:42
  • It worked for me after I added – Hugo Matilla Aug 19 '13 at 08:20
  • @Hugo on which API level did you have to do that? It's working for me after setting padding to 0 on API level >= 14 – Daniele Ricci Oct 31 '13 at 07:42
  • 1
    @DanieleRicci android:minSdkVersion="8" android:targetSdkVersion="17". I use ActionbarSherlock, the imageview is different depending on the Version. I do this: if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) icon = (ImageView) findViewById(android.R.id.home); else icon = (ImageView) findViewById(R.id.abs__home); Hope it helps :) – Hugo Matilla Oct 31 '13 at 10:58
  • @Hugo thank you. I ended up doing the same thing but with appcompat ActionBar. It's a shame Google didn't provide any "standard" way to do this. – Daniele Ricci Oct 31 '13 at 14:27
20

I found an other resolution (reference appcompat-v7 ) that change the toolbarStyle ,following code:

<item name="toolbarStyle">@style/Widget.Toolbar</item>


<style name="Widget.Toolbar" parent="@style/Widget.AppCompat.Toolbar">
    <item name="contentInsetStart">0dp</item>
</style>
jhondge
  • 2,352
  • 1
  • 17
  • 13
  • Thank you!!! Only your solution worked for me. The accepted answer is great, but in my case home button was always shown. With your solution I got clear action bar with my custom view filled to the width of screen. Now I can add my own home button to it with my width and behaviour. – lobzik Jan 31 '15 at 13:43
  • 1
    Please elaborate more on this solution. I mean, where do I need to add this code? I have a custom style for my action bar. – AndroidGuy Apr 15 '15 at 09:55
  • @AndroidGuy Use above theme style to which activity you want remove left space forexample: In your manifest activity node. use attribute "theme" reference to your custom theme. and then in your custom theme config item that: @style/Widget.Toolbar like above. – jhondge Apr 16 '15 at 12:22
  • When you update the appcompat support library to v22.1.1 ,You must use actionBarStyle value to replace toolbarStyle. Because ActionBar content inset value isnot use toolbarStyle's property. – jhondge May 26 '15 at 08:51
11

use custom layout for ActionBar

enter image description here

public class TestActivity extends Activity {

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

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

        setContentView(R.layout.main);

    }

    public void Click(View v) {
        if (v.getId() == R.id.imageIcon) {
            Log.e("click on-->  ", "Action icon");
        }
    }
}

actionbar_custom_view_home.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center" >

    <ImageView
        android:id="@+id/imageIcon"
        android:onClick="Click"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Large Icon With Title"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>
Dhaval Parmar
  • 18,812
  • 8
  • 82
  • 177
  • This is a boilerplate code for custom actionbar view, but it doesn't remove the padding/margin on the left. See http://stackoverflow.com/questions/26433409/android-lollipop-appcompat-actionbar-custom-view-doesnt-take-up-whole-screen-w?lq=1 – s-hunter Apr 02 '16 at 16:55
2

Enhanced parrzhang reply in remove padding around action bar left icon on Android 4.0+

 private void adjustHomeButtonLayout(){
        ImageView view = (ImageView)findViewById(android.R.id.home);
        if(view.getParent() instanceof ViewGroup){
            ViewGroup viewGroup = (ViewGroup)view.getParent();
            View upView = viewGroup.getChildAt(0);
            if(upView != null && upView.getLayoutParams() instanceof FrameLayout.LayoutParams){
                FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) upView.getLayoutParams();
                layoutParams.width = 20;// **can give your own width**
                upView.setLayoutParams(layoutParams);
            }
        }
    }
Community
  • 1
  • 1
Manohar
  • 231
  • 2
  • 4
0

To set the height of ActionBar you can create new Theme like this one:

<?xml version="1.0" encoding="utf-8"?>
<resources>   
    <style name="Theme.BarSize" parent="Theme.Sherlock.Light.DarkActionBar">
        <item name="actionBarSize">48dip</item>
        <item name="android:actionBarSize">48dip</item> 
    </style> 
 </resources>

and set this Theme to your Activity:

android:theme="@style/Theme.BarSize"

Now, set the height of the icons to "match_parent".

That would remove the top and bottom padding.

Now, the arrow at the left is inbuilt into the framework, so you have two options for a workaround:

  1. Use ActionBarSherlock. It uses it's own drwables and resources, so you can modify the arrow icon to an emty png, so that your up icon would move to extreme left.

  2. The up/back icon arises from:

public boolean onOptionsItemSelected(MenuItem item) 
               {
          switch (item.getItemId()) 
                {
                case android.R.id.home:
                            NavUtils.navigateUpFromSameTask(this);
              return true;
                }      
               }

So, instead of using this option for up button, you can make another actionbar option, which has an intent for the previous activity, and then place that icon on your action bar.

It will be a bigger workaround though.

Hope that helps.. :)

Avijit
  • 391
  • 2
  • 21
  • thanks for the answer, but it doesn't answer my question ;-) You say: << Now, set the height of the icons to "match_parent" >> but that is the point.. how? – luca Apr 22 '13 at 04:18
-1

you can find homeview in actionbarview define like this:

<view xmlns:android="http://schemas.android.com/apk/res/android"
  class="com.android.internal.widget.ActionBarView$HomeView"
  android:layout_width="wrap_content"
  android:layout_height="match_parent">
<ImageView android:id="@android:id/up"
           android:src="?android:attr/homeAsUpIndicator"
           android:layout_gravity="center_vertical|start"
           android:visibility="gone"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginEnd="-8dip" />
<ImageView android:id="@android:id/home"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginEnd="8dip"
           android:layout_marginTop="@android:dimen/action_bar_icon_vertical_padding"
           android:layout_marginBottom="@android:dimen/action_bar_icon_vertical_padding"
           android:layout_gravity="center"
           android:adjustViewBounds="true"
           android:scaleType="fitCenter" />

but you cannot get upView by findViewById(android.R.id.up).

so you can get homeView and get its parent view ,set upview width 0

    ImageView view = (ImageView)findViewById(android.R.id.home);
    if(view.getParent() instanceof ViewGroup){
        ViewGroup viewGroup = (ViewGroup)view.getParent();
        View upView = viewGroup.getChildAt(0);
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) upView.getLayoutParams();
        layoutParams.width = 0;
        upView.setLayoutParams(layoutParams);
    }