List View Footer Background on Android 2.3.3-ThrowExceptions

Exception or error:

This one is weird. I have a list view that is a part of Relative Layout. I have set a background to this Relative Layout and made list view background as transparent.

Now, everything was working great till this morning. I could see the whole screen covered with my custom background even if there is just one row in my list view.

Then, I got update on Verizon Motorola Droid X for 2.3.3 (it was 2.2 before). Once it was updated, I started my app again and now here is what happens.

If my list view has only one row, I see a white area below it and not my custom background.
But if it has say 100 rows and thus covers the whole screen I won’t see that weird white background. My relative layout has width and height set to “fill_parent”.

I have posted my XML at the bottom. Has anyone else faced this problem or I am making some really stupid mistake.

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background = "@drawable/background" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ListView   android:id = "@+id/listQueue"
                android:layout_width = "fill_parent"
                android:layout_height = "fill_parent"
                android:layout_below = "@id/homeScreenBanner"
                android:background="@android:color/transparent"
                android:divider="@drawable/separator"
                android:scrollingCache="false"/>
</RelativeLayout>

EDIT:

I think I have found the solution to this problem:

Changed the layout_height attribute to wrap_content and it worked like a charm. 🙂

Following the changed line.
android:layout_height = "wrap_content"

How to solve:

I wrote a class that can be used in Android 2.1/2 that will do the right thing in 2.3 using reflection with ListViews:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.ListView;

public class TransparentListView extends ListView {

    private void makeTransparent() {
        if (Build.VERSION.SDK_INT >= 9) {
            try {

                Method overscrollFooterMethod = 
                    TransparentListView.class.getMethod("setOverscrollFooter", new Class[] {Drawable.class});
                Method overscrollHeaderMethod = 
                    TransparentListView.class.getMethod("setOverscrollHeader", new Class[] {Drawable.class});


                try {
                    overscrollFooterMethod.invoke(this, new Object[] {null});
                    overscrollHeaderMethod.invoke(this, new Object[] {null});
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    public TransparentListView(Context context) {
        super(context);
        this.makeTransparent();
    }

    public TransparentListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.makeTransparent();
    }

    public TransparentListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.makeTransparent();
    }
}

Use it in XML as follows:

<com.myapp.TransparentListView android:id="@android:id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:transcriptMode="alwaysScroll"
    android:layout_weight="1"
    android:dividerHeight="0dip"
    android:divider="#00000000"
    android:cacheColorHint="#00000000"
/>  

###

There is actually an easy solution to this problem using basic layouts implemented completely in the .xml layout file.

First off, the Motorola blog suggestion is not acceptable because it requires building to API v2.3 in order to use ‘android:overScrollFooter‘ forcing either multiple builds or inaccessibility to the majority of Android devices.

The suggestion to set the ListView’s android:layout_height="wrap_content" does work in many cases and is very useful if there are no layout items below the ListView.

The problem occurs when there are one or more View’s above and one or more View’s below the ListView. This requires setting both android:layout_below and android:layout_above for the ListView, which stretches the height of the ListView to the height of the available space which is bigger than the necessary ‘wrap_content‘. When this happens, the “Bug” kicks in – the extra space at the bottom of the ListView is filled with the footer’s default background color which is dark gray and not transparent.

Now for the simple solution.

Place the ListView inside of a vertical LinearLayout or equivalent. Allow the LinearLayout to span from top to bottom of the available space with height="fill_parent", the extra will be filled with the correct background drawable or color. Set the height of the ListView to "wrap_content" so there is no unused space for the unsightly gray footer background.

Here is an example:

<Button> android:id=@+id/MyTopButton" ... </Button>
<Button> android:id=@+id/MyBottomButton" android:layout_alignParentBottom="true" ... </Button>

<LinearLayout
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    android:orientation="vertical"
    android:layout_below="@+id/MyTopButton"
    android:layout_above="@+id/MyBottomButton"
    >

    <!-- Note: This is a bug fix for a particular problem experienced on 
         Motorola OS v2.3.3 devices only in which the space below the unused 
         portion of the ListView is rendered in gray instead of the desired 
         transparent 'cacheColorHint' color. This solution which wraps the 
         ListView in another container (a LinearLayout in this case) allows 
         the ListView to be of height "wrap_content" while the parent 
         container is forced to be the desired height - namely from the 
         header area above down to the buttons below. -->

    <ListView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/MyList"
        android:cacheColorHint="#00000000"
        />

</LinearLayout>

###

Yes, David’s solution works in some cases and allows you to build with an Android before 2.3. In fact, it’s the first solution I posted on the MotoDev forum, with a downloadable code sample, back in June.

However, some developers said that it leaves an artifact (meaning: a stray horizontal grey line at the bottom of the list). I’ve seen this myself. That doesn’t work for those who care about design detail. The android:overScrollFooter="@null" solution does not leave an artifact. But you’re right, to use it you need to build with Android 2.3 or up.

###

See Motorola’s blog post on this behavior — the answer is that on Motoblur 2.3, they set a default overscroll footer, which is fixable by setting android:overScrollFooter="@null", but only for Android 2.3+.

Their recommended appwide solution is to use a custom theme with a custom listViewStyle set only in the values-v10 folder with that property set.

###

Can you try with setting cacheColorHint of your ListView to transparent?

android:cacheColorHint=”@android:color/transparent”

Leave a Reply

Your email address will not be published. Required fields are marked *