вторник, 7 декабря 2010 г.

Android: как поместить ListView в ScrollView

Сталкивались ли вы с проблемой, когда на экран нужно вывести, помимо списка ListView, другие элементы, и все не умещается на экран по вертикали? Очевидное решение - "обернуть" все в ScrollView. Но здесь неожиданно мы натыкаемся на проблему.

Разработчики Андроида "запрещают" помещать ListView в ScrollView, т.к. у ListView уже есть свой скроллер.

В результате, когда пытаемся поместить ListView в ScrollView, то ListView "сворачивается", в то время, как по задумке он должен быть полностью развернут.

Для того, чтобы "развернуть" ListView, я использую такой хак:

public class Utility {
    public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter(); 
        if (listAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = 0;
        int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
        listView.requestLayout();
    }
}

Вызываем эту функцию после изменения элементов списка, вот так:
Utility.setListViewHeightBasedOnChildren(myListView);

Обновлено 9 февраля 2011: баг исправлен, теперь все работает!

7 комментариев:

  1. Привет. Где исправлен? Что нужно чтобы заработало?

    ОтветитьУдалить
  2. Вопрос, все все сделал, Listview отображается как надо, но почему не работает слушатель нажатия по элементу listview, хотя визуально selector работает, а вот программно OnClickListener yt отрабатывает?

    ОтветитьУдалить
  3. Ren, приведенный мной код уже исправлен и должен работать.

    Sergey, мой код тут ни при чем, у вас проблемы с layout. Попробуйте, например, отключить focusable и focusableInTouchMode для элементов ListView.

    ОтветитьУдалить
  4. добавил, спасибо, работает...но listView получается слишком длинным...как это можно пофиксить?

    ОтветитьУдалить
    Ответы
    1. Мне помогла замена MeasureSpec.AT_MOST -> MeasureSpec.UNSPECIFIED в строке
      int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);

      Удалить
  5. Спасибо огромное, очень помогло.

    ОтветитьУдалить
  6. Все работает отлично до тех пор, пока высота итема в листвью одинаковая. Если же каждый итем в листвью имеет разную высоту то часть листвью обрезается. Возможно это как-нибудь профиксить?

    ОтветитьУдалить