Search code examples
androidandroid-layoutandroid-listviewcolorsandroid-relativelayout

View's Background Color Removed When Using RelativeLayout In ListView


While working with ListViews I ran into an interesting issue. So my goal was to write an xml layout for a custom ListView item design.

First of all, here is the problematic xml layout (problem described below):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:background="?android:attr/activatedBackgroundIndicator" >

    <TextView
        android:id="@+id/notebook_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:textAppearanceLarge"
        android:layout_toRightOf="@+id/notebook_color_tag"
        />

    <View
        android:id="@+id/notebook_color_tag"
        android:layout_width="20dp"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        />

</RelativeLayout>

The layout is fairly basic, just a View, that's used to display a color, and a TextView.

I have a subclass of ListFragment which uses an instance of a subclass of CursorAdapter in its setListAdapter() method. In that custom CursorAdpater's bindView() I set the View's color and the TextView's text (that code is not the problem, you can ignore it, it's just here for referrence):

@Override
public void bindView(View view, Context context, Cursor cursor) {
    TextView notebookName = (TextView) view.findViewById(R.id.notebook_title);
    View colorTag = view.findViewById(R.id.notebook_color_tag);

    String name = cursor.getString(NOTEBOOK_NAME_POS);
    int color = cursor.getInt(NOTEBOOK_COLOR_POS);

    notebookName.setText(name);
    colorTag.setBackgroundColor(color);
}

Now, the problem is that if the View's android:layout_height is set to match_parent or wrap_content, the View simply does not appear in the ListView's items. It seems as it has some margin at the top. If a concrete width value is specified, for example: android:layout_height="40dp", everything works fine.

Here is how the bogus layout looks:

Erroneous ListView

Here is how it should look:

Correct ListView

As explained above, the blue rectangle does not seem to be inside the ListView's item container at all (but the element is there, it's accessible via findViewById() and it's color does get changed via the setBackgroundColor()call, the View simply seems not to be displayed).

The follwoing change to the layout fixes the problem:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="horizontal"
    android:background="?android:attr/activatedBackgroundIndicator" >

    <View
        android:id="@+id/notebook_color_tag"
        android:layout_marginTop="0dp"
        android:layout_width="20dp"
        android:layout_height="match_parent"
        />

    <TextView
        android:id="@+id/notebook_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:textAppearanceLarge"
        />

</LinearLayout>

I understand that LinearLayout makes more sense here than the RelativeLayout, but I'm curious what was wrong in the RelativeLayout's case.


Solution

  • You have duplicate 'notebook_color_tag' ID's. You are adding it twice in the first layout XML (as a parameter in the TextView and also as a child of the layout).

    Also, I would reverse the order, like so:

    <View
        android:id="@+id/notebook_color_tag"
        android:layout_width="20dp"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        />
    
    <TextView
        android:id="@+id/notebook_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:textAppearanceLarge"
        android:layout_toRightOf="@id/notebook_color_tag"
        />
    

    Since the RelativeLayout will create and place in the order of the XML, this is more efficient (it does not have to remeasure to place the views correctly.