tags:

views:

208

answers:

3

Hi,

I have read this blog entry about using relative layout to optimize layout in ListView: http://android-developers.blogspot.com/2009/02/android-layout-tricks-1.html

I have used this layout for my ListView Item (with a slight modification of the example):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"

    android:padding="6dip">

    <ImageView
        android:id="@+id/icon"

        android:layout_width="wrap_content"
        android:layout_height="fill_parent"

        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"
        android:layout_marginRight="6dip"

        android:src="@drawable/icon" />

    <TextView
        android:id="@+id/secondLine"

        android:layout_width="fill_parent"
        android:layout_height="26dip" 

        android:layout_toRightOf="@id/icon"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"

        android:singleLine="true"
        android:ellipsize="marquee"/>

    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"

        android:layout_toRightOf="@id/icon"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_above="@id/secondLine"
        android:layout_alignWithParentIfMissing="true"

        android:gravity="center_vertical" />

</RelativeLayout>

And I have modified the List14.java in APIDemo to use that ListItem View. But when I run it on emulator, I only see the icon, the text is blank. And when I open HierarchyViewer for the text View's height is 0. Can someone please tell me why?

public class TestListView extends ListActivity {

     private static class EfficientAdapter extends BaseAdapter {
            private LayoutInflater mInflater;
            private Bitmap mIcon1;
            private Bitmap mIcon2;

            public EfficientAdapter(Context context) {
                // Cache the LayoutInflate to avoid asking for a new one each time.
                mInflater = LayoutInflater.from(context);

                // Icons bound to the rows.
                mIcon1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon48x48_1);
                mIcon2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon48x48_2);
            }

            /**
             * The number of items in the list is determined by the number of speeches
             * in our array.
             *
             * @see android.widget.ListAdapter#getCount()
             */
            public int getCount() {
                return DATA.length;
            }

            /**
             * Since the data comes from an array, just returning the index is
             * sufficent to get at the data. If we were using a more complex data
             * structure, we would return whatever object represents one row in the
             * list.
             *
             * @see android.widget.ListAdapter#getItem(int)
             */
            public Object getItem(int position) {
                return position;
            }

            /**
             * Use the array index as a unique id.
             *
             * @see android.widget.ListAdapter#getItemId(int)
             */
            public long getItemId(int position) {
                return position;
            }

            /**
             * Make a view to hold each row.
             *
             * @see android.widget.ListAdapter#getView(int, android.view.View,
             *      android.view.ViewGroup)
             */
            public View getView(int position, View convertView, ViewGroup parent) {
                // A ViewHolder keeps references to children views to avoid unneccessary calls
                // to findViewById() on each row.
                ViewHolder holder;

                // When convertView is not null, we can reuse it directly, there is no need
                // to reinflate it. We only inflate a new View when the convertView supplied
                // by ListView is null.
                if (convertView == null) {
                    convertView = mInflater.inflate(R.layout.list_item_icon_text, null);

                    // Creates a ViewHolder and store references to the two children views
                    // we want to bind data to.
                    holder = new ViewHolder();
                    holder.text = (TextView) convertView.findViewById(R.id.text);
                    holder.icon = (ImageView) convertView.findViewById(R.id.icon);

                    convertView.setTag(holder);
                } else {
                    // Get the ViewHolder back to get fast access to the TextView
                    // and the ImageView.
                    holder = (ViewHolder) convertView.getTag();
                }

                // Bind the data efficiently with the holder.
                holder.text.setText(DATA[position]);
                holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);

                return convertView;
            }

            static class ViewHolder {
                TextView text;
                ImageView icon;
            }
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setListAdapter(new EfficientAdapter(this));
        }

        private static final String[] DATA = {
                "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam",

                "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"};
}

}
A: 

Can't tell you exactly why the Blog's example won't run (anymore?). It doesn't run on my emulator either (1.5 & 1.6). I finally got it to run by switching the two TextViews and getting rid of layout_above. Like this:

  <TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"

    android:id="@+id/text"
    android:layout_alignWithParentIfMissing="true"
    android:layout_toRightOf="@id/icon"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    />

<TextView  
    android:id="@+id/secondLine"

    android:layout_width="fill_parent"
    android:layout_height="26dip" 
    android:layout_below="@id/text" 

    android:layout_toRightOf="@id/icon"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    />
rflexor
Thank you. I never thought of doing that.
hap497
In the above example, it said "android:layout_alignParentRight="true", but why when I run in on emulator, the TextView is to the align to LEFT of the parent?
hap497
Not sure if I understood you correctly. Here's what I think: alignParentRight here means "align the right border of TextView _with_ the right border of the parent element" which is the LinearLayout. Of course, that basically means placing the TextView to the left of the right border of the LinearLayout.The text-content of the TextView is aligned to the left because that is the default if you do not set android:gravity on the TextView.Does that help?
rflexor
You said '"align the right border of TextView with the right border of the parent element" which is the LinearLayout.' You meant 'RelativeLayout? There is no LinearLayout in the example?
hap497
Yes, of course, the RelativeLayout. Sorry!
rflexor
A: 

Looks like your layout is a bit muddled. With RelativeLayouts you need to be careful not to contradict yourself with alignmentst, else all sorts of unexpected things happen.

android:layout_alignParentTop="true"
    android:layout_alignParentBottom="true"

Above is an example.

I haven't tried this out and you didn't explain what you wanted to achieve with yout layout, but try the following.

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
>

<ImageView
    android:id="@+id/icon"
    android:src="@drawable/icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_marginRight="6dip"
    />

<TextView
    android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@id/icon"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    />

<TextView
    android:id="@+id/secondLine"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:layout_toRightOf="@id/icon"
    android:layout_below="@id/text"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:singleLine="true"
    android:ellipsize="marquee"
    />

Try to keep your layout definitions in a logical order, it will help with debugging later.

Also have a look at your getView method, it can be a lot simpler.

    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        LayoutInflater vi = 

(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    v = vi.inflate(R.layout.list_item_icon_text, null);

    TextView text = (TextView) convertView.findViewById(R.id.text);
    ImageView icon = (ImageView) convertView.findViewById(R.id.icon);

    icon.setText(DATA[position]);
    icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);

    return v;
}

These examples may not be 100% perfect, but they should get you along the right path.

Snowwire
A: 

I had the same problem, and all I had to do was change the android:layout_toRightOf="@id/icon" to android:layout_toRightOf="@+id/icon"; note the "+" before "id" and viola! Worked like a charm.

-Sree

Sreedevi J