18

Is there a way to get ListViewItem height in code, when there is no actual items in list?

My ListViewItem layout:

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

I have tried to get it using Inflater:

View convertView = LayoutInflater.from( this )
    .inflate( R.layout.mail_list_row, null );
int itemHeight = convertView.getHeight();

But it's return 0;

Thanks!

Maksym Gontar
  • 22,765
  • 10
  • 78
  • 114
  • is there something in your row? because listPreferredItemHeight is a reference to an android resource which is not a value in itself i think : http://developer.android.com/reference/android/R.attr.html#listPreferredItemHeight – Sephy Jul 29 '10 at 10:28
  • at the beginning list is empty – Maksym Gontar Aug 03 '10 at 04:41
  • In the vast majority of cases you simply want a fixed known height. Simply **set the minHeight** in xml in the layout of the cell. That's all there is to it. – Fattie Dec 28 '16 at 19:00

4 Answers4

45

Try this, it will work for you.

private static final int UNBOUNDED = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);

// To calculate the total height of all items in ListView call with items = adapter.getCount()
public static int getItemHeightofListView(ListView listView, int items) {
    ListAdapter adapter = listView.getAdapter();

    int grossElementHeight = 0;
    for (int i = 0; i < items; i++) {
        View childView = adapter.getView(i, null, listView);
        childView.measure(UNBOUNDED, UNBOUNDED);
        grossElementHeight += childView.getMeasuredHeight();
    }
    return grossElementHeight;
}
TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
Ashish Dwivedi
  • 8,048
  • 5
  • 58
  • 78
  • Thanks for the code, this works for getting the size of a row not yet rendered, but the question was asking about the height of a row which is not yet inserted in the ListView. – hariseldon78 Mar 26 '13 at 15:23
  • The rows are formed in the getView methods of the list view adapter, so you can simply find the height of the row in the getView – Ashish Dwivedi Apr 01 '13 at 06:20
  • 1
    @AshishDwivedi I have come across a similar issue, can you please suggest? – Kanth May 30 '13 at 10:04
  • This wont work if you, for example, have a long textview that wraps on multiple lines inside a child view. You need to specify the width. – Sver Aug 20 '13 at 07:49
  • @Appu, Can you please describe your issue. . – Ashish Dwivedi Sep 11 '13 at 13:25
  • @DwivediJi That's fine. I solved it on my own on that day itself. Thanks though for replying after many days. – Kanth Sep 12 '13 at 11:33
  • @Appu, I am not regular user of Stackoverflow. so for .. sorry bro – Ashish Dwivedi Sep 12 '13 at 13:22
  • to @Sver's comment: makeMeasureSpec(listView.getWidth(), android.view.View.MeasureSpec.AT_MOST)) should help as the first argument to measure. – TWiStErRob Oct 06 '13 at 11:50
  • @DwivediJi Why do you need pass "items" as an argument? Is there any problem if I use mAdapter.getCount() instead of "items"? – Ricardo Jan 25 '15 at 21:48
  • @Ricardo You can use mAdapter.getCount() method. kindly modified code according to your code . – Ashish Dwivedi Apr 23 '15 at 05:26
  • measure method gives NullPointerException to me.. I thought it could get the height of the unrendered items.. – Alpaslan Jun 29 '15 at 10:47
13

optimized version of Dwivedi Ji's code with dividers height and without unnecessary params:

private int calculateHeight(ListView list) {

    int height = 0;

    for (int i = 0; i < list.getCount(); i++) {
        View childView = list.getAdapter().getView(i, null, list);
        childView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        height+= childView.getMeasuredHeight();
    }

    //dividers height
    height += list.getDividerHeight() * list.getCount();

    return height;
}
ashakirov
  • 12,112
  • 6
  • 40
  • 40
  • 3
    I think divider count should be `list.getCount() - 1` – osrl Feb 14 '15 at 20:06
  • 1
    And this gives all items height. so `items` parameter is necessary since it tells how many items do you want to add to total height. – osrl Feb 14 '15 at 20:15
5

In android a view is assigned Width and Height only when its rendering is complete. So unless you list is rendered atleast once you won't get listItemHeight. Solution to your problem could be that you set some min Height of list Item so that you have atleast something to work with instead of Hard Coding height and width.

Amit Chintawar
  • 20,450
  • 1
  • 17
  • 17
  • Also [this SO answer](http://stackoverflow.com/questions/4243894/android-listview-item-height/4274505#4274505) seems to point in the direction of `android:minHeight`. – superjos Nov 18 '11 at 09:02
  • Yo bro..hours of trying to set listview height dint work to me in a gud way. but setting minHeight gave me a ray of hope. – Rushi Ayyappa Aug 20 '17 at 03:23
4

As hariseldon78 above points out none of these solutions fix the REAL problem which is determining the height of the list item row BEFORE it is rendered. I had the same problem as I wanted to scale some images to the height of my ListView item rows, and did not want to scale them to a fixed value. If the theme caused the text in other parts of my row layout to vary in height, I wanted the height so that in my getView routine of my adapter I could resize the bmap accordingly. I was struggling with the problem that getHeight and all the measured heights report zero until the row has been rendered. FOr me seeing the heights correct later was too late.

My solution is to create an onLayoutChangedListener() the first time through getView and only for row 0. The listener will trigger as soon as getView for the first position (0) completes executing, and at that time the "bottom" parameter will tell you the height of the row. I record this in a custom adapter class variable so it is available as a height parameter without having to fetch the height again.

The listener unregisters itself as part of its execution. This provides the proper height for rows 1-N but not for row zero. For row zero I did something really nasty. I had my listener call getView AGAIN for row 0 after setting another custom adapter class variable to control the recursion. The second time getView(0) runs it will not setup the listener, and will find a valid parameter for height to operate with and all is good.

Code is below - no need to tell me how AWFUL this is - if android didn't have to make it so freaking hard to tell how big the view I am creating is when I am done populating the view's based on the rendering parms for the surface I wouldn't have to do this ugliness but it works. Sorry if the code formatting is awful ...

int mHeight = 0;

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
... usual boiler plate stuff
    // JUST THE FIRST TIME
    if (position == 0 && mHeight == 0) {
        final View ref = convertView;
        convertView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            public void onLayoutChange(View v, int left, int top, int right,
                   int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    ref.removeOnLayoutChangeListener(this);
                    mHeight = bottom;
                    firstTime = false;

                    //  NOW LETS REGET THE FIRST VIEW WITH THE HEIGHT CORRECT
                    int visiblePosition = getListView().getFirstVisiblePosition();
                    View view = getListView().getChildAt(0 - visiblePosition);
                    getListAdapter().getView(0, view, getListView());
                    // RECURSION LOL
            }
        });
    }

    // Configure the view for this row
    ....

    // HOW BIG IS THE VIEW?
    // NOW IF NOT FIRSTTIME (MHEIGHT != 0)
    if (mHeight != 0) {
        // DO OUR IMAGE SETUP HERE CAUSE mHeight is RIGHT!
        Log.d(TAG, "mHeight=" + mHeight);
    }

        return convertView;
}
Mike Kogan
  • 278
  • 3
  • 10
  • You could use the following layout to give you something like you wanted in the first paragraph in pseudo-android-xml: `` – TWiStErRob Jun 06 '15 at 22:53
  • @MikeKogan Thanks, This worked for me too. I was having issue with screens in the same size bucket but different resolutions. Until there's a better way to solve this, it seems like the way to go. – Adam Mendoza Jul 16 '16 at 21:01