Android - Get ListView item height?

35,281

Solution 1

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.

Solution 2

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;
}

Solution 3

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;
}

Solution 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;
}
Share:
35,281
mohsin shabir
Author by

mohsin shabir

Currently coding in swift for iOS at SciForce and working on Master Degree in Data Science at UCU (Lviv). "Useful information should be shared, commercial - kept, dangerous - destroyed" (coder etique) "There is little difference between know and know how to find" (Lucy S.) "Work without fun is like bread without jam" (conversation between designer and coder)

Updated on June 07, 2020

Comments

  • mohsin shabir
    mohsin shabir almost 4 years

    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!