Android - Get ListView item height?
Asked Answered
M

4

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!

Mccaskill answered 29/7, 2010 at 10:17 Comment(3)
is there something in your row? because listPreferredItemHeight is a reference to an android resource which is not a value in itself i think : developer.android.com/reference/android/…Sacken
at the beginning list is emptyMccaskill
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.Alica
A
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.

Aluminate answered 29/7, 2010 at 13:23 Comment(2)
Also this SO answer seems to point in the direction of android:minHeight.Casual
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.Bettyebettzel
J
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;
}
Jocose answered 20/9, 2012 at 13:39 Comment(11)
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.Suppression
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 getViewJocose
@AshishDwivedi I have come across a similar issue, can you please suggest?Sesquipedalian
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.Diametrically
@Appu, Can you please describe your issue. .Jocose
@DwivediJi That's fine. I solved it on my own on that day itself. Thanks though for replying after many days.Sesquipedalian
@Appu, I am not regular user of Stackoverflow. so for .. sorry broJocose
to @Sver's comment: makeMeasureSpec(listView.getWidth(), android.view.View.MeasureSpec.AT_MOST)) should help as the first argument to measure.Opposition
@DwivediJi Why do you need pass "items" as an argument? Is there any problem if I use mAdapter.getCount() instead of "items"?Cartload
@Cartload You can use mAdapter.getCount() method. kindly modified code according to your code .Jocose
measure method gives NullPointerException to me.. I thought it could get the height of the unrendered items..Newmint
R
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;
}
Roup answered 7/10, 2014 at 12:57 Comment(2)
I think divider count should be list.getCount() - 1Footlight
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.Footlight
A
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.

Aluminate answered 29/7, 2010 at 13:23 Comment(2)
Also this SO answer seems to point in the direction of android:minHeight.Casual
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.Bettyebettzel
L
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;
}
Lineolate answered 5/1, 2014 at 23:23 Comment(2)
You could use the following layout to give you something like you wanted in the first paragraph in pseudo-android-xml: <LinearLayout orientation="horizontal" width="fill" height="wrap"><ImageView width="wrap" height="fill" scaleType="fitCenter" adjustViewBounds /><TextView width="0dp" weight="1.0" height="wrap" />Opposition
@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.Outfox

© 2022 - 2024 — McMap. All rights reserved.