Dynamically change the row height in a listview based on number of list items
Asked Answered
C

3

6

I was creating an Android Application in which I use a ListView. The ListView consists of CheckedTextView list items. My activity contains an EditText at the top, a TextView below that and a Button at the bottom. The space between the TextView and the button is the area occupied by the ListView. Now, since my ListView contains rather few items, the entire space of the ListView is not occupied by them. Also the space left obviously varies across devices. What I want to know is if there is a way to alter the row height of ListView so that the entire space alloted to the ListView is covered. And also if there occurs a need to add some items the row height may adjust itself accordingly. I have provided some code snippets below so that it is easy to understand what my Layout is like.

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="#D0D0D0"
tools:context=".MainActivity" >

<Button
    android:id="@+id/addcourse"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:text="Add Course" />

<EditText
    android:id="@+id/coursenameet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:ems="10"
    android:layout_marginBottom="2dp"
    android:layout_marginTop="2dp"
    android:hint="Course Name" 
    android:inputType="textCapWords" >

    <requestFocus />
</EditText>

<View
    android:id="@+id/divider"
    android:layout_width="match_parent"
    android:layout_height="3dp"
    android:layout_below="@+id/coursenameet"
    android:layout_marginBottom="5dp"
    android:layout_marginTop="5dp"
    android:background="@android:color/darker_gray" >
</View>

<TextView
    android:id="@+id/weekdaytv"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/divider"
    android:layout_marginBottom="3dp"
    android:layout_marginTop="3dp"
    android:layout_centerHorizontal="true"
    android:text="Select weekdays for this Course" >
</TextView>

<ListView
    android:id="@+id/listView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@+id/addcourse"
    android:layout_below="@+id/weekdaytv"
    android:divider="#FFFFFF"
    android:dividerHeight="2px">

</ListView>

</RelativeLayout>

The items are CheckedTextViews that are implemented using BaseAdapter. The View method of BaseAdapter class is

public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    int colorpos = position % colors.length;
    if(v == null){
        LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.listviewitem, null);
    }
    CheckedTextView newrow = (CheckedTextView) v.findViewById(R.id.checkedtextview);
    v.setBackgroundColor(colors[colorpos]);
    newrow.setTextColor(Color.BLACK);
    newrow.setText(items[position]);
    return v;
}

EDIT: Snippet from Main Activity

lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    adapter = new ItemsAdapter(MainActivity.this, weekdays, 6, lv.getBottom() - lv.getTop());
    lv.setAdapter(adapter);

    lv.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
            CheckedTextView ctv = (CheckedTextView) arg1;
            adapter.toggle(ctv);
        }
    });
Carothers answered 14/6, 2013 at 13:10 Comment(1)
Got any right solution ?Bozovich
D
11

Hi Create a class like this

public class Utility {

    public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = 0;
        int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
        listView.requestLayout();
    }


 }

Call this method at where do you want dynamically change the row height in a listview.

 Utility.setListViewHeightBasedOnChildren(YourListView);

For more Reference.. Hope this will help you.

Dickey answered 14/6, 2013 at 13:47 Comment(8)
I have declared the appearance of my rows in the BaseAdapter Class. Please tell me what exactly is this going to do?? Also I am setting my adapter using :- lv.setAdapter(adapter); Am I supposed to call this method just after that? Assume I have fixed number of rows right now and I am not adding any rows at the moment.Carothers
just declare your listview in that method. it will give you exactly what do you want.Dickey
I am really sorry but I fail to understand you. I have edited my question and put up a snippet of the main activity code to let you see what exactly I am doing. Suggest where I should call the method.Carothers
call after this line lv.setAdapter(adapter); Utility.setListViewHeightBasedOnChildren(lv);Dickey
I did. It doesn't change anything. Are you sure this should work?Carothers
I used this code. it will work perfectly.. if you got more doubt about this. just click that reference..Dickey
I saw the reference. It says almost the same thing that you answered. It doesn't help. :( Also I am not sure if you understood my question completely. I apologize if I was not able to convey my question properlyCarothers
@Dickey Thank you brother..your answer helped me thank you so much..upvoted for you :)Paralogism
R
0

To set your ListView to fill the entire space allotted, you can set the listView attribute in XML:

android:fillViewport=”true”

Or in code:

myListView.setFillViewport(true);

If you want to change the size of a cell, you can calculate the ViewParams to set. For example, for a single cell, you can use:

AbsListView.LayoutParams params = new AbsListView.LayoutParams(AbsListView.LayoutParams.FILL_PARENT, AbsListView.LayoutParams.FILL_PARENT);
v.setLayoutParams(params);

For n cells, you can calculate the vertical size based on the size of your ListView:

int n = /* number of cells */ 3;
int height = (myListView.getBottom() - myListView.getTop());
AbsListView.LayoutParams params = new AbsListView.LayoutParams(AbsListView.LayoutParams.FILL_PARENT, height/n);
v.setLayoutParams(params);
Rodriques answered 14/6, 2013 at 13:17 Comment(5)
It gives an error :- Open quote is expected for attribute "android:fillViewport" associated with an element type "ListView". Please Help.Carothers
Please tell me what is myCell in the last line of your answer. I do not have a corresponding value in my code. Also tell me if this is to be done in the main activity or the BaseAdapter class that I have.Carothers
AbsListView.LayoutParams params = new AbsListView.LayoutParams(AbsListView.LayoutParams.FILL_PARENT, height/n); In this line FILL_PARENT is being struck out/deprecated by Eclipse. Also I cannot use myListView.getBottom() because the listview declaration is in another class, not the BaseAdapter Class. Please help!!Carothers
@tintin, you will need to find the height you need some other way then. As for FILL_PARENT: you can swap it out for MATCH_PARENT.Rodriques
I did. I passed the number of rows and height to the constructor of the BaseAdapter Class and also changed the FILL_PARENT to MATCH_PARENT. But it the list view still is what it was earlier. The rows don't fill up the entire area alloted to the ListViewCarothers
D
0

For those who still got error at

 listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);

write these lines of code, like this.

if (listItem instanceof ViewGroup)

listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

        listItem.measure(0, 0);
Disenable answered 26/10, 2013 at 5:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.