Android: Removing Fade Effect on ActionBar when using setActionView()

Letting me start by explaining the desired effect I was trying to achieve. On the Android Google+ application if you hit refresh there is a spinner animation that replaces the refresh ActionBar item when pressed. I was able to achieve this but setting the pressed MenuItem to a new layout by using “MenuItem.setActionView()”.

However, on ICS if you have a two ore more MenuItems always available in the Android ActionBar (i.e. you set android:showAsAction=”ifRoom” in the mainmenu.xml file below) swapping the the icon on one MenuItem when pressed causes a slight ghost selection of the other.

The MenuItem next to the one pressed immediately shows a highlight as you stop pressing the refresh icon. This ghost selection behavior is produced because the default ICS background selector contains a fade animation. Swapping the icon causes the animation up/fade to transfer to the next non-customized ActionBar MenuItem, the one you didn’t select.

Here is a code example (not complete) on how to swap out the MenuItem with a custom spinner:

private View mRefreshIndeterminateProgressView; // save inflated layout for reference
private MenuItem refreshItem; // reference to actionbar menu item we want to swap

if (mRefreshIndeterminateProgressView == null) {
   LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   mRefreshIndeterminateProgressView = inflater.inflate(R.layout.actionbar_indeterminate_progress, null);
}
refreshItem.setActionView(mRefreshIndeterminateProgressView); // replace actionbar menu item with progress
// doing refreshItem.setActionView(null) removes the animation

Here is what the actionbar_indeterminate_progress.xml looks like:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:gravity="center"> 
<ProgressBar android:layout_width="16dp" 
    android:layout_height="16dp" 
    android:layout_marginLeft="12dp" 
    android:layout_marginRight="12dp" 
    android:layout_gravity="center" 
    style="?android:attr/indeterminateProgressStyle"/> 
</FrameLayout> 

Here is your mainmenu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@+id/detail_menu_refresh" 
    android:title="Refresh" 
    android:icon="@drawable/ic_action_refresh" 
    android:showAsAction="ifRoom"/> 

 <item android:id="@+id/main_menu_share" 
    android:title="Share" 
    android:icon="@drawable/ic_action_share"
    android:showAsAction="ifRoom"/>

 <item android:id="@+id/main_menu_about" 
    android:title="About" 
    android:icon="@drawable/ic_action_about"
    android:showAsAction="never"/>

 </menu>

The solution is to set your own custom selector background for the ActionBar so you can remove the fade. To do this, I grabbed the abs__item_background_holo_dark.xml from (ActionBarSherlock > Library > res > drawable) and the associated graphics to add to my project. You could easily do this without using ActionBarSherlock and just ActionBar and regular themes for your project. I then removed the following line from the nod in the xml which disables the fade:

 android:exitFadeDuration="@android:integer/config_mediumAnimTime" 

Here is modified abs__item_background_holo_dark.xml:

 
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_disabled_holo_dark" />
    <item android:state_focused="true"  android:state_enabled="false" android:drawable="@drawable/abs__list_selector_disabled_holo_dark" />
    <item android:state_focused="true"  android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_dark" />
    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_dark" />
    <item android:state_focused="true"  android:drawable="@drawable/abs__list_focused_holo" />
    <item  android:drawable="@android:color/transparent" />
</selector>

Here is how I set it up in my styles.xml file:

 
<style name="Dark" parent="Theme.Sherlock.Light.DarkActionBar">
    <item name="actionBarStyle">@style/Widget.Styled.ActionBar</item>
    <item name="android:actionBarStyle">@style/Widget.Styled.ActionBar</item>
    <item name="actionBarItemBackground">@drawable/abs__item_background_holo_dark</item>
    <item name="android:actionBarItemBackground">@drawable/abs__item_background_holo_dark</item>
</style>

<style name="Widget.Styled.ActionBar" parent="Widget.Sherlock.Light.ActionBar.Solid.Inverse"/>

I got a great tip on how to fix this from Jake Wharton, the creator of ActionBarSherlock. I recommend using his library if you want to have a consistent ActionBar across all versions of your Android applications.

– Mister

Android: Changing the Default Indeterminate Progress Size in ActionBarSherlock

Just a quick post on how to change the default size of the Indeterminate Progress animation when using ActionBarSherlock (ABS). This uses the dark halo them for Android 4.0.1 but tested and working from version 2.3.2 to 4.0.1 of the SDK. Here are the before and after shots:

Grab the progress_small_holo.xml and associated images from the Android SDK (15) and move them to your project (from your SDK location: android/platforms/android-15/data/res/drawable). We will be using this to style the progress animation in the ActionBar for ABS Set up your style.xml as follows:

values/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Dark" parent="Theme.Sherlock">
        <item name="actionBarStyle">@style/Widget.Styled.ActionBar</item>
        <item name="android:actionBarStyle">@style/Widget.Styled.ActionBar</item>
    </style>

    <style name="Widget.Styled.ActionBar" parent="Widget.Sherlock.Light.ActionBar">
        <item name="android:indeterminateProgressStyle">@style/IndeterminateProgress</item> 
        <item name="indeterminateProgressStyle">@style/IndeterminateProgress</item> 
    </style>

    <style name="IndeterminateProgress" parent="@android:style/Widget.ProgressBar.Small"> 
       <item name="android:indeterminateDrawable">@drawable/progress_small_holo</item> 
   </style> 
</resource>

values-v14/styles.xml (ICS)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Dark" parent="Theme.Sherlock">
        <item name="actionBarStyle">@style/Widget.Styled.ActionBar</item>
        <item name="android:actionBarStyle">@style/Widget.Styled.ActionBar</item>
    </style>

    <style name="Widget.Styled.ActionBar" parent="Widget.Sherlock.Light.ActionBar">
        <item name="android:indeterminateProgressStyle">@style/IndeterminateProgress</item> 
        <item name="indeterminateProgressStyle">@style/IndeterminateProgress</item> 
    </style>

    <style name="IndeterminateProgress" parent="@android:style/Widget.ProgressBar.Small"/> 

</resource>

You could also add some additional sizing if you want to center the progress animation in the actionbar:

<style name="IndeterminateProgress" parent="@android:style/Widget.ProgressBar.Small">
       <item name="android:minWidth">48dp</item> 
</style>

You can see more of the discussion on this thread or from StackOver.

-Mister