Android - 获取 ListView 项目高度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3361423/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:54:26  来源:igfitidea点击:

Android - Get ListView item height?

androiduser-interfacelistviewlayoutlistviewitem

提问by Maksym Gontar

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

当列表中没有实际项目时,有没有办法在代码中获取 ListViewItem 高度?

My ListViewItem layout:

我的 ListViewItem 布局:

<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:

我尝试使用 Inflater 获取它:

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

But it's return 0;

但它的返回 0;

Thanks!

谢谢!

采纳答案by Amit Chintawar

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.

在android中,只有在渲染完成时才会为视图分配宽度和高度。因此,除非您的列表至少在您不会获得 listItemHeight 时呈现。您的问题的解决方案可能是您设置了列表项的一些最小高度,以便您至少有一些可以使用的东西,而不是硬编码的高度和宽度。

回答by Dwivedi Ji

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

回答by ashakirov

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

Dwivedi Ji带有分隔高度且没有不必要参数的代码的优化版本:

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

回答by Mike Kogan

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.

正如上面的 hariseldon78 所指出的,这些解决方案都没有解决真正的问题,即在呈现列表项行之前确定它的高度。我遇到了同样的问题,因为我想将一些图像缩放到我的 ListView 项目行的高度,并且不想将它们缩放到固定值。如果主题导致行布局其他部分的文本高度不同,我想要高度,以便在我的适配器的 getView 例程中,我可以相应地调整 bmap 的大小。我一直在努力解决 getHeight 和所有测量的高度报告零直到该行被渲染的问题。对我来说,后来看到高度正确为时已晚。

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.

我的解决方案是第一次通过 getView 创建一个 onLayoutChangedListener() 并且只针对第 0 行。一旦第一个位置 (0) 的 getView 完成执行,监听器就会触发,届时“bottom”参数会告诉你行的高度。我将其记录在自定义适配器类变量中,因此它可以作为高度参数使用,而无需再次获取高度。

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.

侦听器在其执行过程中将自身注销。这为第 1-N 行提供了适当的高度,但不为第 0 行提供了适当的高度。对于第零行,我做了一些非常讨厌的事情。在设置另一个自定义适配器类变量以控制递归后,我让我的侦听器再次为第 0 行调用 getView。第二次 getView(0) 运行时,它不会设置监听器,并且会找到一个有效的高度参数来操作,一切都很好。

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 ...

代码如下 - 无需告诉我这是多么糟糕 - 如果 android 不需要让它如此可怕地告诉我创建的视图有多大,当我完成基于渲染参数填充视图时表面上我不必做这种丑陋的事情,但它确实有效。对不起,如果代码格式很糟糕......

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