Search code examples
androidandroid-layoutandroid-listviewandroid-linearlayoutandroid-compatibility

how to work around change in list item layout behavior change between sdk 17 and 18?


I've created a simple app to illustrate a change in how LinearLayout behaves when wrapped in a RelativeLayout between SDK 17 and SDK 18. First, screenshots:

When targetSdkVersion is "17":

enter image description here

When targetSdkVersion is "18":

enter image description here

The layout for this activity is:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ffff"
    android:orientation="vertical" >

    <include layout="@layout/test_list_item"/>

    <ListView
        android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:overScrollMode="never"
        android:scrollingCache="false" >
    </ListView>

</LinearLayout>

text_list_item.xml is:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ff0000" >

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="#ffff00"
        android:padding="10dp"
        android:text="foobar"
        android:textColor="#000000" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignBottom="@id/text"
        android:layout_alignTop="@id/text"
        android:background="#00ff00"
        android:orientation="horizontal"
        android:weightSum="1.0" >

        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="0.5"
            android:background="#0000ff" />
    </LinearLayout>

</RelativeLayout>

The activity's onCreate() looks like this:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    findViewById(R.id.text).bringToFront();
    final ListView mListView = (ListView) findViewById(R.id.listview);
    mListView.setAdapter(new TestAdapter());
}

And TestAdapter looks like this:

public class TestAdapter extends BaseAdapter {

    private static final int COUNT = 3;

    @Override
    public int getCount() {
        return COUNT;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return true;
    }

    @Override
    public boolean isEnabled(int position) {
        return false;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_list_item, null);
        view.findViewById(R.id.text).bringToFront();
        return view;
    }

When target = 17 the LinearLayout's child view is properly resized to 50% of available width both when it's inside the ListView and when it's outside the ListView. When target = 18 it's not resized when used as the layout for a list item. In this case its width stays at "0dp" and is never resized.

Ideally I would like to target SDK 19. In order to do so, though, I to accommodate this change in behavior somehow. Any thoughts on how that could be accomplished?

btw, There are reasons why the layout is as complicated and "weird" as it is; I realize there are much more straightforward ways of achieving this particular visual look.

EDIT:

To give a little more info on why I'm using this pathological layout: its used for "gauges". The View inside the LinearLayout is stretched or shrunk using a ScaleAnimation so that it occupies the desired percentage of the total available width. What makes it tricky is that I need to overlay text on top of the gauge, and I'd like the gauge's height to be determined by the text.

So the exterior RelativeLayout should be "as wide as its parent" but only "as tall as the TextView it contains". The LinearLayout inside that RelativeLayout should be exactly as wide and tall as its parent. The View inside the LinearLayout should be as tall as the LinearLayout that contains it, but only half as wide.

This is exactly the behavior I get when targeting SDK 17 and/or in SDK 18+ when the layout isn't used as the contents of a ListView item.

EDIT

Posted on the developer's group:

https://groups.google.com/forum/#!msg/android-developers/KuoY5Tklyms/TbNq6ndD_PwJ


Solution

  • Looks like since its just a view and nothing has to be rendered, for some optimization sake measure methods were skipped. Change View to TextView and set some text and u will see it does appears as expected. I do understand that LinearLayout rendered the View differently(not sure if thats correct or ListView is correct)

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ff0000" >
    
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="#ffff00"
        android:padding="10dp"
        android:text="foobar"
        android:textColor="#000000" />
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignBottom="@id/text"
        android:layout_alignTop="@id/text"
        android:background="#00ff00"
        android:orientation="horizontal"
        android:weightSum="1.0" >
    
        <TextView
            android:id="@+id/testView"
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="0.5"
            android:background="#0000ff"
            android:singleLine="false" />
    </LinearLayout>
    

     @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list_item, null);
    
            view.findViewById(R.id.text).bringToFront();
            TextView testView = (TextView)view.findViewById(R.id.testView);
            testView.setText("some test text for viewNo:"+String.valueOf(position));
    
            return view;
        }
    

    enter image description here