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:
Here is how it should look:
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.
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.