Вычислите размер представления списка или как рассказать, чтобы он полностью расширялся

В настоящее время я пытаюсь использовать ListView внутри ScrollView. Я знаю, из того, что я прочитал, это выглядит сверху вниз, но я пытаюсь полностью расширить ListView, показывая все его строки, поэтому нет необходимости прокручивать его. Однако я боролся с тем, как показать, что ListView полностью расширяется, чтобы показать все его строки, так как ему нужна определенная высота. Кто-нибудь знает способ вычисления высоты полностью расширенного ListView до его рисования?

Эта проблема в основном связана с тем, что вы не можете поместить прокручиваемый вид внутри другого прокручиваемого представления. Я в порядке с тем, что ListView не сможет прокручивать, пока я могу его расширить, чтобы показать все его строки. Однако я не могу этого сделать, не имея возможности дать ему определенную высоту, что, по-видимому, мне нужно будет вычислить.

Посмотрите URL-адрес ниже для эскиза (я новый пользователь, поэтому мне не разрешено публиковать его). Он показывает, что мой полный макет слишком велик для "физического" экрана и ему нужно прокрутить, чтобы показать остальную часть списка и кнопки внизу. Я пытаюсь понять, что "виртуальный" экран слишком велик, чтобы соответствовать одному экрану даже без ListView.

http://img51.imageshack.us/img51/7210/screenmockup.png

Ответ 1

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

1) Создайте новый класс, который расширяет ListView:

package com.example.android.views;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.ListView;

public class ExpandedListView extends ListView {

    private android.view.ViewGroup.LayoutParams params;
    private int old_count = 0;

    public ExpandedListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (getCount() != old_count) {
            old_count = getCount();
            params = getLayoutParams();
            params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);
            setLayoutParams(params);
        }

        super.onDraw(canvas);
    }

}

2)... и, наконец, добавим новое представление в ваш файл макета xml:

<com.example.android.views.ExpandedListView
    android:id="@+id/list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scrollbars="none"
    android:padding="0px"
    />

Ответ 2

Правильный способ расчета высоты точно:

int height = 0;
for (int i = 0; i < listView.getChildCount(); i++) {
    height += listView.getChildAt(i).getMeasuredHeight();
    height += listView.getDividerHeight();
}

Ответ 3

Внимание! Правильный способ расчета высоты не

params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);

Мы должны добавить высоту каждой (минус одной) высоты разделителя.

if(oldCount > 0 && getCount() > 0)
    params.height = getCount()
                  * (getChildAt(0).getHeight() + getDividerHeight())
                  - getDividerHeight();
else
    params.height = 0;

Ответ 4

Если вы хотите, чтобы ListView, который не будет прокручиваться, не мог бы просто использовать LinearLayout?

Ответ 5

@Override
public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
    if (this.isExpanded) {
        final int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
        final ViewGroup.LayoutParams params = this.getLayoutParams();
        params.height = this.getMeasuredHeight();
    } else {
       super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

Ответ 6

Нельзя размещать ListView в ScrollView. ListView уже прокручивается.

ListView должен полностью развернуться по умолчанию, если это единственное в макете.

Если это не единственное в макете, и вы хотите, чтобы ListView расширялся, чтобы заняться всем свободным пространством, установите layout_weight в ListView равным 1, где все остальные layout_weight = 0.

<LinearLayout android:layout_width="fill_parent" 
             android:layout_height="fill_parent" orientation="vertical">
  <TextView id="@+id/title" 
             android:layout_width="wrap_content" 
            android:layout_height="wrap_content"/>
  <ListView id="@+id/listView" 
            android:layout_width="fill_parent" 
            android:layout_height="0dp" 
            android:layout_weight="1"/>
</LinearLayout>

Изменить: ListView действительно предназначен для прокрутки... макет экрана, который у вас есть на скриншоте, на самом деле не похож на "андроидный путь".

Однако, если вы действительно хотите обойти это, вы можете попробовать раздуть одну из строк, получить ее minHeight и умножить на количество элементов в адаптере ListView.

LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.label_value_row, null, false);
int height = adapter.getCount() * view.getMinHeight();

Ответ 7

Я взял функцию из ответа djunod (функция в статическом классе)

рассчитать размер списка просмотров

и измените метод ondraw следующим образом. он успешно работает после успешных операций удаления.

вот мой последний класс

класс ExpandedListView расширяет ListView {

private android.view.ViewGroup.LayoutParams params;
private int old_count = 0;

public ExpandedListView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
protected void onDraw(Canvas canvas) {

    if (getCount() != old_count) {
        params = getLayoutParams();
        old_count = getCount();
        int totalHeight = 0;
        for (int i = 0; i < getCount(); i++) {
            this.measure(0, 0);
            totalHeight += getMeasuredHeight();
        }

        params = getLayoutParams();
        params.height = totalHeight + (getDividerHeight() * (getCount() - 1));
        setLayoutParams(params);
    }

    super.onDraw(canvas);
}

}

теперь мой список расширяется после вставки строки без прокрутки. и после удаления строки этот код вычисляет правильный размер для списка. Я не знаю, как он работает. но он работает. BR

Ответ 8

Я закончил переопределять onDraw() ListView и вычислял среднюю высоту видимых строк в представлении, а затем оценивал фактическую высоту списка в зависимости от количества элементов в адаптере. Эта оценка выполняется несколько раз, пока все строки не будут видны.

Ответ 9

Я изучал, как это сделать, и хотя на этот вопрос уже был дан ответ, я хотел бы предложить решение, которое, я думаю, будет лучше:

Глядя на исходный код ListView, вы можете увидеть следующее внутри кода onMeasure (...):

if (heightMode == MeasureSpec.AT_MOST) {
     // TODO: after first layout we should maybe start at the first visible position, not 0
     heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
}

Так просто вызовите меру listView и передайте MeasureSpec.AT_MOST для высоты вместо обычного MeasureSpec.UNSPECIFIED.

Я делаю следующее, чтобы измерить список и поместить его во всплывающее окно:

    int widthMeasureSpec = MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, MeasureSpec.EXACTLY);
    int heightMeasureSpec = MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, MeasureSpec.AT_MOST);
    mCatalogView.measure(widthMeasureSpec, heightMeasureSpec);

    mPopup.setWidth(mCatalogView.getMeasuredWidth());
    mPopup.setHeight(mCatalogView.getMeasuredHeight());

Ответ 10

Я знаю это поздно, и есть уже и ответ, но если вы действительно хотите сделать это, вам будет проще:

Создать представление списка Элемент с определенной высотой

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/lvItemSurpriseMeImgRestaurant"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_marginLeft="5dp"
        android:contentDescription="@string/restaurantImageDescriptionColon" />
</LinearLayout>

Теперь мы знаем, что элемент 100dp высокий, и если мы знаем количество элементов, то это очень просто

установите высоту ListView буквально в значение NoOfItems * Height + 10dp extra

Он никогда не изменится, поскольку все объединения находятся в dp.

Если у вас более одного типа элемента, то вычислите его с помощью базовой математики и установите его

        <ListView
            android:id="@+id/menuListView"
            android:layout_width="match_parent"
            android:layout_height="210dp"
            android:layout_weight="1.0"
            tools:ignore="NestedScrolling"
            tools:listitem="@layout/menu_item" >
        </ListView>

Ответ 11

Если у вас есть элементы с разной высотой, вам нужно использовать этот метод:

public void setListViewHeightBasedOnChildren(ListView listView) {

    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter != null) {

        int numberOfItems = listAdapter.getCount();

        // Get total height of all items.
        int totalItemsHeight = 0;
        for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
            View item = listAdapter.getView(itemPos, null, listView);
            float px = 300 * (listView.getResources().getDisplayMetrics().density);
            item.measure(
                    View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            int height = item.getMeasuredHeight();
            totalItemsHeight += height;
        }

        // Get total height of all item dividers.
        int totalDividersHeight = listView.getDividerHeight() *
                (numberOfItems - 1);

        // Set list height.
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalItemsHeight + totalDividersHeight;
        listView.setLayoutParams(params);
        listView.requestLayout();
    }
}

он отлично работает с любым ListView с любыми элементами

Ответ 12

использовать это будет:

public class ListViewEx extends ListView {

public ListViewEx(Context context) {
    super(context);
}

/**
 * @param context
 * @param attrs
 */
public ListViewEx(Context context, AttributeSet attrs) {
    super(context, attrs);
}

/**
 * 设置不滚动
 */
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, expandSpec);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    return ev.getAction()==MotionEvent.ACTION_MOVE||super.dispatchTouchEvent(ev);
}

}