Android - Получить ListView высота элемента? - PullRequest
18 голосов
/ 29 июля 2010

Есть ли способ получить высоту ListViewItem в коде, когда в списке нет реальных элементов?

Мой макет ListViewItem:

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

Я пытался получить его с помощью Inflater:

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

Но это возвращение 0;

Спасибо!

Ответы [ 4 ]

42 голосов
/ 20 сентября 2012

Попробуйте, это будет работать для вас.

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;
}
11 голосов
/ 07 октября 2014

оптимизированная версия кода 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;
}
4 голосов
/ 29 июля 2010

В андроид представлению назначаются ширина и высота только после завершения рендеринга. Поэтому, если ваш список не будет отображен как минимум, вы не получите listItemHeight. Решение вашей проблемы может заключаться в том, что вы задаете минимальную высоту элемента списка так, чтобы у вас было как минимум что-то, с чем можно работать, а не высота и ширина жесткого кодирования.

2 голосов
/ 06 января 2014

Как указано выше в hariseldon78, ни одно из этих решений не решает проблему REAL, которая определяет высоту строки элемента списка ДО того, как она будет отображена. У меня возникла та же проблема: я хотел масштабировать некоторые изображения до высоты строк моего элемента ListView и не хотел масштабировать их до фиксированного значения. Если из-за темы текст в других частях макета строки менялся по высоте, я хотел, чтобы высота была такой, чтобы в моей подпрограмме getView адаптера я мог соответствующим образом изменить размер карты. Я боролся с проблемой, что getHeight и все измеренные высоты сообщают ноль, пока строка не будет отрисована. Для того, чтобы я увидел правильные высоты позже, было слишком поздно.

Мое решение состоит в том, чтобы создать onLayoutChangedListener () в первый раз через getView и только для строки 0. Слушатель сработает, как только завершится выполнение getView для первой позиции (0), и тогда параметр "bottom" скажет вам высоту ряда. Я записываю это в пользовательскую переменную класса адаптера, чтобы она была доступна в качестве параметра высоты без необходимости извлекать высоту снова.

Слушатель отменяет регистрацию как часть своего выполнения. Это обеспечивает правильную высоту для строк 1-N, но не для нулевой строки. Для нулевого ряда я сделал что-то действительно противное. У меня был вызов прослушивателя getView AGAIN для строки 0 после установки другой переменной класса адаптера для управления рекурсией. Во второй раз, когда getView (0) запустится, он не настроит слушателя и найдет допустимый параметр для высоты, с которым будет работать, и все хорошо.

Код приведен ниже - не нужно рассказывать мне, как это УЖАСНО - если андроид не должен был уследить, чтобы сказать, насколько велик мой вид, когда я заканчиваю заполнять вид на основе рендеринга Пармс на поверхность Мне бы не пришлось заниматься этим безобразием, но это работает. Извините, если форматирование кода ужасное ...

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