Блог веб-разработчика v 1.0.0
Symfony2, AngularJS, React, Gulp, PhpStorm и много других страшных слов

ListView внутри ScrollView

10 лет назад
14364 просмотра
Android Google Полезности

Если вы разрабатываете под Андройд, то наверняка сталкивались с задачей заставить ListView растягиваться по высоте своего контента, например чтобы поместить его внутрь ScrollView вместе с другими элементами. На самом деле подобный подход не рекомендуется использовать, т.к. ListView создавался не для этого, но мы не ищем легких путей и иногда проще "тупо сделать вот так".

Первое решение которое приходит в голову: назначить высоту wrap_content для ListView. Это не работает. Можете даже не пробовать, максимум чего вы добьетесь это растяжения высоты на первый элемент списка.

После еще некоторых попыток заставить список тянуться по высоте начинается гугление. К сожалению, гугл не выдает конкретного ответа на вопрос, только наводки и предложения. Все сводится к тому, чтобы вручную измерять общую высоту элементов списка и назначать списку сумарную высоту. Если вы хорошо разбираетесь в Андройде, наверное, это не будет проблемой, а для таких как я предлагаю готовое решение, честно найденное на просторах StackOverflow:

public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null)
        return;

    int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.UNSPECIFIED);
    int totalHeight = 0;
    View view = null;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        view = listAdapter.getView(i, view, listView);
        if (i == 0)
            view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT));

        view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
        totalHeight += view.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
    listView.requestLayout();
}

Этот метод нужно вызвать на нашем ListView после заполнения всех элементов. Все проверено и работает в Android 4.0+ (API 14+). На более ранних версиях честно не проверял, но думаю проблем быть не должно.

Есть еще один мелкий момент, который возможно кому-то пригодится. Если у вас используются разделители списка (divider), то нужно заменить одну строчку на это:

params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount()));

Т.е. по сути убрать "минус один".

Так же будет интересно

Дополнительно советую почитать про Push уведомления на Android или посмотреть мою реализацию выезжающей панели на Android.

Что еще почитать
Выезжающая панель на Android
10 лет назад
17990 просмотров
Вчера мне понадобилось сделать панель наподобие стандартной верхней панели Android, той самой которую вы ежедневно вытаскиваете пальцем из-за верхнего края экрана. Поскольку опыта для написания собственного View подобного рода у меня нет, я начал поиск готовых решений.