Как я могу поместить ListView в ScrollView без его разрушения?

Я искал решения этой проблемы, и, похоже, единственный ответ, который я могу найти, это "не помещайте ListView в ScrollView ". Я еще не нашел реального объяснения почему. Единственная причина, по которой я могу найти, это то, что Google не думает, что вам стоит этого делать. Хорошо, я так и сделал.

Итак, вопрос в том, как вы можете поместить ListView в ScrollView, не уменьшая его до минимальной высоты?


person DougW    schedule 16.08.2010    source источник
comment
Их аргумент против этого, похоже, состоит в том, что у вас не должно быть одной прокручиваемой вещи внутри другой. А почему бы и нет? Я далеко не фанат Apple, но они, кажется, думают, что это разумная вещь, которую кто-то может захотеть сделать.   -  person DougW    schedule 16.08.2010
comment
Потому что, когда устройство использует сенсорный экран, нет хорошего способа различить два вложенных прокручиваемых контейнера. Он работает на традиционных рабочих столах, где вы используете полосу прокрутки для прокрутки контейнера.   -  person Romain Guy    schedule 16.08.2010
comment
Конечно, есть. Если они касаются внутренней части, прокрутите ее. Если внутренний слишком большой, это плохой дизайн пользовательского интерфейса. Это не значит, что это вообще плохая идея.   -  person DougW    schedule 16.08.2010
comment
@Romain, мне любопытно, были ли просмотры списков с горизонтальной прокруткой в ​​приложении новостей и погоды Google. Было ли это сделано с помощью viewflipper, галереи или горизонтальной прокрутки, заполненной объектами listview?   -  person Nadewad    schedule 08.04.2011
comment
@Romain Самое забавное, что два вложенных контейнера отлично работают в отношении событий касания. Единственная проблема в том, что Listview не расширяется, чтобы заполнить его родителем.   -  person HRJ    schedule 20.04.2011
comment
Просто наткнулся на это для своего приложения для планшета. Хотя на смартфоне это не кажется слишком худшим, на планшете это ужасно, где вы легко можете решить, хочет ли пользователь прокручивать внешний или внутренний ScrollView. @DougW: Ужасный дизайн, согласен.   -  person jellyfish    schedule 06.07.2011
comment
@Romain - это довольно старый пост, поэтому мне интересно, были ли проблемы здесь уже решены, или все еще нет хорошего способа использовать ListView внутри ScrollView (или альтернативы, которая не требует ручного кодирования все тонкости ListView в LinearLayout)?   -  person Jim    schedule 04.04.2013
comment
Нет, извините.   -  person Romain Guy    schedule 04.04.2013
comment
@Jim: или альтернатива, которая не требует ручного кодирования всех тонкостей ListView в LinearLayout - поместите все в ListView. ListView может иметь несколько стилей строк, а также невыбираемые строки.   -  person CommonsWare    schedule 05.04.2013
comment
@CommonsWare есть ли способ, если я использую GridView?   -  person Nemanja Kovacevic    schedule 21.08.2013
comment
Руководства по дизайну материалов Google инструктируют вас использовать nestedScrollView с cardView, который содержит listView.   -  person Luke Allison    schedule 01.06.2016
comment
Дело в том, почему ListView (или RecyclerView) должен иметь возможность прокрутки? У RecyclerView есть одна основная функция: переработка. ScrollView имеет одну функцию: прокрутка. Почему они не могли работать вместе? RecyclerView может обрабатывать свои перерабатываемые ячейки в соответствии с видимой областью, выделенной средством scrollview. Да, это сложнее закодировать, но это имеет смысл.   -  person Benoit    schedule 09.08.2016
comment
Добавьте nestedScrollView вместо Scrollview, он будет работать нормально.   -  person Taimoor    schedule 05.10.2016


Ответы (28)


Использование ListView для предотвращения прокрутки чрезвычайно дорого и противоречит цели ListView. Вы должны НЕ этого делать. Просто используйте вместо этого LinearLayout.

person Romain Guy    schedule 16.08.2010
comment
Не спорю с вашей точкой зрения, но можете ли вы процитировать источник, который говорит о том, насколько это дорого и почему? Переработка списка элементов в LinearLayout кажется намного более затратной с точки зрения времени разработки. Я хотел бы знать, почему это так дорого, и сам принять такое решение. - person DougW; 16.08.2010
comment
Источником мог бы быть я, так как я отвечал за ListView последние 2 или 3 года :) ListView делает много дополнительной работы по оптимизации использования адаптеров. Попытка обойти это все равно приведет к тому, что ListView будет выполнять много работы, которую LinearLayout не должен делать. Я не буду вдаваться в подробности, потому что здесь недостаточно места для объяснения реализации ListView. Это также не решит проблему поведения ListView в отношении событий касания. Также нет гарантии, что если ваш взлом работает сегодня, он будет работать и в будущем выпуске. На самом деле использование LinearLayout не составит большого труда. - person Romain Guy; 16.08.2010
comment
Что ж, это разумный ответ. Если бы я мог поделиться некоторыми отзывами, у меня гораздо более значительный опыт работы с iPhone, и я могу сказать вам, что документация Apple намного лучше написана в отношении характеристик производительности и вариантов использования (или анти-шаблонов), подобных этому. В целом документация Android гораздо более распределена и менее сфокусирована. Я понимаю, что для этого есть несколько причин, но это долгая дискуссия, поэтому, если вы чувствуете необходимость поговорить об этом, дайте мне знать. - person DougW; 17.08.2010
comment
Значит, нет возможности это сделать? Это очень распространено и тривиально на iPhone, и я ищу аналог для Android для использования. Есть ли обходной путь? - person w.donahue; 26.01.2011
comment
Я не уверен, что это также верно для ListView внутри HorizontalScrollView или наоборот. Звучит как совершенно законный вариант использования для меня? - person andig; 23.02.2011
comment
Есть ли эквивалентный список без прокрутки на основе адаптера? LinearLayout не использует адаптер. Я пытаюсь повторно использовать существующий адаптер списка. - person James Wald; 20.12.2011
comment
Вы можете легко написать статический метод, который создает LinearLayout из адаптера. - person Romain Guy; 20.12.2011
comment
@Romain Guy: есть ли подсказка об использовании не прокручиваемого listView для gridView? что, если я хочу иметь сетку с постоянным количеством элементов, которые можно обновить, щелкнув где-нибудь на экране? - person android developer; 10.07.2012
comment
Лучший способ добавить элементы, как если бы они находились в listview внутри scrollview, - это LinearLayout.addView(View view, LayoutParams params);. Я также создаю Map с парами ключ-значение, которые помогают мне отслеживать, какой элемент был добавлен по какому индексу и как я могу получить доступ к данным. - person prometheuspk; 15.07.2012
comment
Меня это несколько раз расстраивало. Это выглядит так: 1, вы составляете список со списком, думая, что это все, что вам нужно. 2: впоследствии дизайн добавляется кнопкой / текстовым полем / всем, что идет над или под списком. Listview не позволяет этого. 3: вам нужно выбросить реализацию listview и начать все сначала. Вывод: никогда не используйте listview, если вы не абсолютно уверены, что это все, что вам когда-либо понадобится в дизайне. - person Karl; 15.08.2012
comment
@Karl ListView позволяет это. Вы можете использовать верхние / нижние колонтитулы, если хотите, чтобы кнопка / текстовое поле / что угодно прокручивались вместе со списком. - person Romain Guy; 30.08.2012
comment
@RomainGuy, это правда. Раньше я использовал его только для обивки. В некоторых моих реализациях я мог бы использовать верхний и нижний колонтитулы вместо того, чтобы начинать заново, спасибо за напоминание! Но можно ли добавить несколько заголовков? - person Karl; 31.08.2012
comment
@RomainGuy, моя реализация в порядке? Я также перестал использовать Map и отправляю свой объект в конструктор моего View - person prometheuspk; 05.09.2012
comment
Это НЕ ответ на _1 _... Вы можете сказать, что вам не следует этого делать, но вы также можете дать ответ, как это сделать, это хороший ответ. Вы знаете, что у ListView есть и другие интересные функции, помимо прокрутки, которых нет в LinearLayout. - person Jorge Fuentes González; 23.06.2013
comment
Что делать, если у вас есть область, содержащая ListView + другие представления, и вы хотите, чтобы все прокручивалось как одно целое? Это кажется разумным вариантом использования для размещения ListView в ScrollView. Замена ListView на LinearLayout не является решением, потому что тогда вы не сможете использовать адаптеры. - person Barry Fruitman; 08.08.2013
comment
хорошо, попробуйте ответить на мой вопрос: у меня макет 400 dpi (портрет) со списком внутри, все работает нормально, но когда я МЕНЯЮ ВИД НА ПЕЙЗАЖ (я поворачиваю свой телефон), общая высота экрана меньше 400 dpi , вот почему нам нужно взломать listview внутри scrollview. - person Bhimbim; 29.10.2013
comment
@RomainGuy: Привет, как ты имеешь в виду Just use a LinearLayout instead? Вы имеете в виду, что прагматично создавать LinearLayout для каждого элемента данных? - person hguser; 20.11.2013
comment
Всегда есть альтернатива творчеству. Это просто требует смелости от UX-дизайнеров. - person Gökhan Barış Aker; 12.02.2014
comment
прекратите спорить об этом, это не решит вопрос, кто-то уже нашел решение, это ОТВЕТ Моисеса Ольмедо: stackoverflow.com/questions/6210895/ - person Bhimbim; 03.03.2014
comment
Вот настоящая приятная идея, как сделать это с помощью linearlayout - если вы создадите линейный макет и включите несколько идентичных макетов с помощью тегов <include />, у вас не будет уникального идентификатора в ваших подпредставлениях, и вы потеряете любое состояние просмотра, если ваше действие будет воссоздано. Это, по-видимому, то, о чем обычно заботятся адаптеры listview +. - person Sam; 11.06.2015
comment
Руководства по дизайну материалов Google показывают примеры вложенныхScrollViews, содержащих cardView, которые содержат listView. - person Luke Allison; 01.06.2016
comment
@RomainGuy как насчет ответа, данного Джейсоном Y ниже ?? - person KJEjava48; 12.07.2019

Вот мое решение. Я новичок в платформе Android, и я уверен, что это немного взломано, особенно в части прямого вызова .measure и непосредственной установки свойства LayoutParams.height, но это работает.

Все, что вам нужно сделать, это вызвать Utility.setListViewHeightBasedOnChildren(yourListView), и он будет изменен, чтобы точно соответствовать высоте его элементов.

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

        int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();

        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            if (listItem instanceof ViewGroup) {
                listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
             }

             listItem.measure(0, 0);
             totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
    }
}
person DougW    schedule 16.08.2010
comment
Вы только что воссоздали очень дорогой LinearLayout :) - person Romain Guy; 16.08.2010
comment
За исключением того, что LinearLayout не обладает всеми присущими ListView тонкостями - у него нет разделителей, представлений верхнего / нижнего колонтитула, селектора списка, который соответствует цветам темы пользовательского интерфейса телефона и т. Д. Честно говоря, нет причин, по которым вы можете ' • прокрутите внутренний контейнер, пока он не достигнет конца, а затем перестаньте перехватывать события касания, чтобы прокрутить внешний контейнер. Каждый настольный браузер делает это, когда вы используете колесо прокрутки. Сам Android может обрабатывать вложенную прокрутку, если вы перемещаетесь с помощью трекбола, так почему бы не с помощью касания? - person Neil Traft; 27.08.2010
comment
Для решения DoughW есть ошибка, но я исправил ее, см. мой пост. - person Nex; 08.12.2010
comment
Если у меня есть элемент списка, например. TextView, а в некоторых случаях он будет содержать две строки текста (или более) вместо одной, тогда высота всего ListView измеряется неправильно. Есть решение для этого? - person croogie; 10.10.2011
comment
Это может быть медленным, но когда у вас есть макет, которого вы должны придерживаться, это поможет! - person Rasmus Øvlesen; 17.01.2012
comment
listItem.measure(0,0) выдаст NPE, если listItem является экземпляром ViewGroup. Перед listItem.measure я добавил следующее: if (listItem instanceof ViewGroup) listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - person Siklab.ph; 21.02.2012
comment
Я создаю горизонтальное представление списка ... и это помогает получить размер представления, просто пропустив строку. :) - person CoDe; 04.03.2013
comment
Исправление для ListView с заполнением, отличным от 0: int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom(); - person Paul; 08.04.2013
comment
К сожалению, этот метод немного ошибочен, если ListView может содержать элементы переменной высоты. Вызов getMeasuredHeight() возвращает только заданную минимальную высоту, а не фактическую высоту. Я попытался использовать вместо этого getHeight(), но это возвращает 0. Есть ли у кого-нибудь представление о том, как к этому подойти? - person Matt Huggins; 09.06.2013
comment
Чтобы ответить на свой вопрос сверху, я исправил это, изменив вызов на measure(0, 0). Вместо этого этому методу следует передать известную ширину и неуказанную высоту через MeasureSpec.makeMeasureSpec(). Для ширины укажите режим измерения MeasureSpec.AT_MOST, а для высоты укажите MeasureSpec.UNSPECIFIED. Передайте результаты этих двух вызовов listItem.measure(). - person Matt Huggins; 09.06.2013
comment
если у кого-то возникнут какие-либо незначительные проблемы после его использования, где ваше представление макета начинается с конца ListView, прежде чем вы даже начнете прокрутку. просто вызовите widget.setFocusableInTouchMode (true); widget.requestFocus (); (где виджет может быть виджетом, который вы выбираете в своем макете) после вызова Utility.setListViewHeightBasedOnChildren (yourListView); - person irobotxx; 14.06.2013
comment
Это плохая идея или нет? Я не уверен, что смогу его использовать. - person KarenAnne; 17.07.2013
comment
@KarenAnne - Вы могли бы использовать это, чтобы выстрелить себе в ногу, но это неплохая идея. Производительность не должна быть проблемой, если вы не используете ее для загрузки огромного списка с большим количеством изображений или чего-то в этом роде. Он отлично работал у нас 3 года назад, когда мы начали его использовать, и за это время устройства стали намного мощнее. - person DougW; 18.07.2013
comment
У меня сработало, спасибо, но есть одна проблема! когда макет загружен, я не вижу верхнюю часть макета. Я дал прокрутку вверх, чтобы увидеть верхнюю часть. Пожалуйста помоги! - person TharakaNirmana; 23.07.2013
comment
Я не знаю, почему он занимает большую высоту bcz, высота моего элемента представления списка составляет 70, и при печати этой строки listItem.getMeasuredHeight () он показывает 316, поэтому я запутался - person duggu; 29.08.2013
comment
Я использую приведенный выше код, и он работает нормально, но нижний колонтитул отсутствует в представлении ... Как я могу это исправить. - person Madhu; 30.01.2014
comment
Если в ListView нет элементов, то последняя строка выглядит так: params.height = totalHeight + (listView.getDividerHeight () * (0 - 1)); или params.height = totalHeight - listView.getDividerHeight (); Но зачем нам выводить dividerHeight, если у нас нет элементов? Это ошибка? - person alcsan; 17.04.2014
comment
Я не знаю, почему у меня это не работает. Небольшая прокрутка все еще есть. - person Rishabh Srivastava; 25.04.2014
comment
Решение @MattHuggins Yous для переменной высоты элемента списка не работает в моем случае. Любое предложение? - person Khobaib; 26.04.2014
comment
Пока работает очень хорошо. Единственное, что с этим кодом - это то, что нижний горизонтальный разделитель нижнего элемента списка не отображается. Чтобы исправить это, в этой строке: params.height = totalHeight + (listView.getDividerHeight () * (listAdapter.getCount () - 1)); просто удалите - 1. - person JDJ; 23.05.2014
comment
Я исправил высоту списка прямо из xml. И да, мой список прокручивается для некоторых устройств (Nexus 4, HTC One). Но на некоторых устройствах не прокручивается. Что здесь не так? - person Reaz Murshed; 09.09.2014
comment
Строка listItem.measure(...) вызовет исключение NullPointerException, если мы используем addHeaderView в вашем ListView. - person Guicara; 25.09.2014
comment
У меня была аналогичная проблема, но в моем случае все элементы списка имеют одинаковую высоту, поэтому вместо цикла for я просто умножил высоту listitem на количество listitems для вычисления totalHeight. - person Seshu Vinay; 04.11.2014
comment
Для всех, кто получает NPE в listItem.measure (...), убедитесь, что XML-макет строки списка - LinearLayout, а не какой-либо другой, потому что другие макеты (например, RelativeLayout) не переопределяют onMeasure () ... - person Marko Niciforovic; 24.11.2014
comment
Последний список внутри scrollview сокращает последний элемент каждый раз, когда он обновляется. - person pratz9999; 06.04.2015
comment
@RomainGuy, если бы вы, ребята, не написали такой ужасный SDK, не было бы такого требования для такого количества хаков. Еще есть открытые ошибки с 2010 года! - person StackOverflowed; 09.06.2015
comment
View.MeasureSpec.EXACTLY работал у меня до этого, это был View.MeasureSpec.AT_MOST, и он добавлял дополнительное пространство внизу, например, если у меня есть 2 элемента в списке, он добавит 2 дополнительных места для элементов в конце списка. Всегда отличное решение - person umerk44; 30.11.2015
comment
но это позволит listview.setSelection(int) не работать. :( - person DysaniazzZ; 16.02.2017

Это определенно сработает ............
Вам нужно просто заменить свой <ScrollView ></ScrollView> в XML-файле макета этим Custom ScrollView, например <com.tmd.utils.VerticalScrollview > </com.tmd.utils.VerticalScrollview >

package com.tmd.utils;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;

public class VerticalScrollview extends ScrollView{

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

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

        public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" );
                    super.onTouchEvent(ev);
                    break;

            case MotionEvent.ACTION_MOVE:
                    return false; // redirect MotionEvents to ourself

            case MotionEvent.ACTION_CANCEL:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" );
                    super.onTouchEvent(ev);
                    break;

            case MotionEvent.ACTION_UP:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" );
                    return false;

            default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break;
        }

        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        super.onTouchEvent(ev);
        Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
         return true;
    }
}
person Atul Bhardwaj    schedule 10.12.2012
comment
Это очень хорошо. Это также позволяет разместить фрагмент Google Maps внутри ScrollView, и он по-прежнему работает с увеличением / уменьшением масштаба. Спасибо. - person Magnus Johansson; 08.08.2013
comment
Кто-нибудь заметил минусы такого подхода? Боюсь, это так просто: o - person Marija Milosevic; 22.10.2014
comment
Хорошее решение, должен быть принятый ответ +1! Я смешал его с ответом ниже (от djunod), и он отлично работает! - person tanou; 16.12.2014
comment
Это единственное исправление, из-за которого у меня одновременно работают прокрутка и щелчок по детям. Большое спасибо - person pellyadolfo; 15.09.2016

После помещения ListView в ScrollView, мы можем использовать ListView как ScrollView. То, что должно быть в ListView, можно поместить внутрь ListView. Другие макеты сверху и снизу ListView можно разместить, добавив макеты в верхний и нижний колонтитулы ListView. Таким образом, весь ListView даст вам возможность прокрутки.

person Arun    schedule 31.12.2012
comment
Это самый элегантный и подходящий ответ imho. Дополнительные сведения об этом подходе см. В этом ответе: stackoverflow.com/a/20475821/1221537 - person adamdport; 10.03.2015

Существует множество ситуаций, в которых имеет смысл иметь ListView в ScrollView.

Вот код, основанный на предложении DougW ... работает во фрагменте, занимает меньше памяти.

public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null) {
        return;
    }
    int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
    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();
}

вызовите setListViewHeightBasedOnChildren (listview) для каждого встроенного списка.

person djunod    schedule 20.07.2013
comment
Это не будет работать, если элементы списка имеют переменные размеры, то есть какое-то текстовое представление, которое расширяется на несколько строк. Любое решение? - person Khobaib; 26.04.2014
comment
Посмотрите мой комментарий здесь - он дает идеальное решение - stackoverflow.com/a/23315696/1433187 - person Khobaib; 26.04.2014
comment
работал у меня с API 19, но не с API 23: здесь он добавляет много белого пространства под listView. - person Lucker10; 26.07.2016

ListView на самом деле уже способен измерять себя, чтобы быть достаточно высоким для отображения всех элементов, но он не делает этого, когда вы просто указываете wrap_content (MeasureSpec.UNSPECIFIED). Он будет делать это, если задана высота с помощью MeasureSpec.AT_MOST. Обладая этими знаниями, вы можете создать очень простой подкласс для решения этой проблемы, который работает намного лучше, чем любое из решений, опубликованных выше. Вы все равно должны использовать wrap_content с этим подклассом.

public class ListViewForEmbeddingInScrollView extends ListView {
    public ListViewForEmbeddingInScrollView(Context context) {
        super(context);
    }

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

    public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
    }
}

Манипулирование heightMeasureSpec как AT_MOST с очень большим размером (Integer.MAX_VALUE >> 4) приводит к тому, что ListView измеряет всех своих дочерних элементов до заданной (очень большой) высоты и соответственно устанавливает свою высоту.

Это работает лучше, чем другие решения, по нескольким причинам:

  1. Все правильно измеряет (отступы, разделители)
  2. Он измеряет ListView во время прохода измерения
  3. Из-за # 2 он правильно обрабатывает изменения ширины или количества элементов без какого-либо дополнительного кода.

С другой стороны, вы можете утверждать, что это зависит от недокументированного поведения в SDK, которое может измениться. С другой стороны, вы можете возразить, что именно так wrap_content действительно должен работать со ListView и что текущее поведение wrap_content просто нарушено.

Если вас беспокоит, что поведение может измениться в будущем, вам следует просто скопировать функцию onMeasure и связанные с ней функции из ListView.java в свой собственный подкласс, а затем сделать путь AT_MOST через onMeasure также для НЕПРЕДВИДЕННОГО.

Кстати, я считаю, что это совершенно правильный подход, когда вы работаете с небольшим количеством элементов списка. Это может быть неэффективно по сравнению с LinearLayout, но когда количество элементов невелико, использование LinearLayout является ненужной оптимизацией и, следовательно, ненужной сложностью.

person Jason Y    schedule 17.04.2015
comment
Также работает с элементами переменной высоты в списке! - person Denny; 17.09.2018
comment
@Jason Y, что это значит Integer.MAX_VALUE ›› 4 ?? что там 4 ?? - person KJEjava48; 11.07.2019
comment
@Jason Y для меня это сработало только после того, как я изменил Integer.MAX_VALUE ›› 2 на Integer.MAX_VALUE ›› 21. Почему это так? Также он работает с ScrollView, а не с NestedScrollView. - person KJEjava48; 12.07.2019

Для этого есть встроенная настройка. В ScrollView:

android:fillViewport="true"

В Java

mScrollView.setFillViewport(true);

Ромен Гай подробно объясняет это здесь: http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/

person TalkLittle    schedule 04.08.2014
comment
Это работает для LinearLayout, как он демонстрирует. Это не работает для ListView. Судя по дате этого сообщения, я полагаю, он написал его, чтобы предоставить пример своей альтернативы, но это не отвечает на вопрос. - person DougW; 04.08.2014
comment
это быстрое решение - person ; 26.05.2017

Вы создаете настраиваемый ListView, который не прокручивается

public class NonScrollListView extends ListView {

    public NonScrollListView(Context context) {
        super(context);
    }
    public NonScrollListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                    Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();    
    }
}

В вашем файле ресурсов макета

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <!-- com.Example Changed with your Package name -->

    <com.Example.NonScrollListView
        android:id="@+id/lv_nonscroll_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </com.Example.NonScrollListView>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/lv_nonscroll_list" >

        <!-- Your another layout in scroll view -->

    </RelativeLayout>
</RelativeLayout>

В файле Java

Создайте объект вашего customListview вместо ListView, например: NonScrollListView non_scroll_list = (NonScrollListView) findViewById (R.id.lv_nonscroll_list);

person Dedaniya HirenKumar    schedule 24.05.2016

Мы не могли использовать две прокрутки одновременно. Мы получим общую длину ListView и развернем listview с общей высотой. Затем мы можем добавить ListView в ScrollView напрямую или с помощью LinearLayout, потому что у ScrollView непосредственно один дочерний элемент. скопируйте метод setListViewHeightBasedOnChildren (lv) в свой код и разверните listview, после чего вы можете использовать listview внутри scrollview. \ layout xml файл

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
 <ScrollView

        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
         android:background="#1D1D1D"
        android:orientation="vertical"
        android:scrollbars="none" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#1D1D1D"
            android:orientation="vertical" >

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="40dip"
                android:background="#333"
                android:gravity="center_vertical"
                android:paddingLeft="8dip"
                android:text="First ListView"
                android:textColor="#C7C7C7"
                android:textSize="20sp" />

            <ListView
                android:id="@+id/first_listview"
                android:layout_width="260dp"
                android:layout_height="wrap_content"
                android:divider="#00000000"
               android:listSelector="#ff0000"
                android:scrollbars="none" />

               <TextView
                android:layout_width="fill_parent"
                android:layout_height="40dip"
                android:background="#333"
                android:gravity="center_vertical"
                android:paddingLeft="8dip"
                android:text="Second ListView"
                android:textColor="#C7C7C7"
                android:textSize="20sp" />

            <ListView
                android:id="@+id/secondList"
                android:layout_width="260dp"
                android:layout_height="wrap_content"
                android:divider="#00000000"
                android:listSelector="#ffcc00"
                android:scrollbars="none" />
  </LinearLayout>
  </ScrollView>

   </LinearLayout>

onCreate в классе Activity:

 import java.util.ArrayList;
  import android.app.Activity;
 import android.os.Bundle;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
  import android.widget.ListView;

   public class MainActivity extends Activity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.listview_inside_scrollview);
    ListView list_first=(ListView) findViewById(R.id.first_listview);
    ListView list_second=(ListView) findViewById(R.id.secondList);
    ArrayList<String> list=new ArrayList<String>();
    for(int x=0;x<30;x++)
    {
        list.add("Item "+x);
    }

       ArrayAdapter<String> adapter=new ArrayAdapter<String>(getApplicationContext(), 
          android.R.layout.simple_list_item_1,list);               
      list_first.setAdapter(adapter);

     setListViewHeightBasedOnChildren(list_first);

      list_second.setAdapter(adapter);

    setListViewHeightBasedOnChildren(list_second);
   }



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

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

    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight
            + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    listView.setLayoutParams(params);
      }
person Ashish Saini    schedule 12.07.2014
comment
Хорошее исправление! Работает как надо. Спасибо. В моем случае у меня есть целая куча представлений перед списком, и идеальное решение - иметь только одну вертикальную прокрутку на представлении. - person Proverbio; 23.07.2014

Это единственное, что у меня сработало:

на Lollipop и далее вы можете использовать

yourtListView.setNestedScrollingEnabled(true);

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

person JackA    schedule 07.11.2016
comment
Это не повлияло на мои представления списка в API 22 в DialogFragment в действии AppCompat. Они все еще рушатся. ответ @Phil Ryan работал с небольшими изменениями. - person Hakan Çelik MK1; 02.05.2018

Не следует помещать ListView в ScrollView, потому что ListView уже является ScrollView. Это все равно что поместить ScrollView в ScrollView.

Что вы пытаетесь достичь?

person Cheryl Simon    schedule 16.08.2010
comment
Я пытаюсь создать ListView внутри ScrollView. Я не хочу, чтобы мой ListView был прокручиваемым, но нет простого свойства для установки myListView.scrollEnabled = false; - person DougW; 16.08.2010
comment
Как сказал Ромен Гай, это не совсем цель ListView. ListView - это представление, оптимизированное для отображения длинного списка элементов с большим количеством сложной логики для отложенной загрузки представлений, повторного использования представлений и т. Д. Ничего из этого не имеет смысла, если вы говорите ListView не прокручивать. Если вам просто нужна группа элементов в вертикальном столбце, используйте LinearLayout. - person Cheryl Simon; 16.08.2010
comment
Проблема в том, что ListView предоставляет ряд решений, в том числе и то, что вы упомянули. Однако большая часть функций, которые упрощают адаптеры, связана с управлением данными и контролем, а не с оптимизацией пользовательского интерфейса. IMO должен был быть простой ListView и более сложный, который выполняет все повторное использование элементов списка и прочее. - person DougW; 17.08.2010
comment
Абсолютно согласен. Обратите внимание, что использовать существующий адаптер с LinearLayout легко, но мне нужны все приятные вещи, которые предоставляет ListView, например разделители, и которые мне не хочется реализовывать вручную. - person Artem Russakovskii; 17.06.2011
comment
@ArtemRussakovskii Не могли бы вы объяснить, как легко заменить ListView на LinearLayout с помощью существующего адаптера? - person happyhardik; 12.09.2012
comment
У меня есть простой пример того, зачем нужен ListView внутри ScrollView. На самом деле у меня есть активность с двумя ListView и кучей других элементов. Конечно, когда я заполняю один из двух списков сверх определенного предела, он заполняет весь экран и требует некоторой прокрутки, чтобы добраться до нижней части экрана. Шаблоны пользовательского интерфейса не должны иметь запутанных ограничений, даже если их иногда можно оптимизировать. - person Bamaco; 04.04.2015

Это комбинация ответов DougW, Good Guy Greg и Paul. Я обнаружил, что все это было необходимо при попытке использовать это с настраиваемым адаптером listview и нестандартными элементами списка, иначе listview вылетел из приложения (также разбился с ответом Nex):

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

        int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            if (listItem instanceof ViewGroup)
                listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
    }
person Abandoned Cart    schedule 04.08.2013
comment
Где вызвать этот метод? - person Dhrupal; 29.07.2014
comment
После создания списка и настройки адаптера. - person Abandoned Cart; 25.08.2014
comment
Это становится слишком медленным в длинных списках. - person cakan; 31.12.2015
comment
@cakan Он также был написан двумя годами ранее как обходной путь, позволяющий использовать вместе определенные компоненты пользовательского интерфейса, которые на самом деле не предназначены для объединения. Вы добавляете ненужные накладные расходы в современном Android, поэтому следует ожидать, что список будет замедляться, когда он станет большим. - person Abandoned Cart; 02.04.2016

Я преобразовал Utility @ DougW в C # (используется в Xamarin). Следующее отлично работает для элементов с фиксированной высотой в списке и будет в основном хорошо или, по крайней мере, хорошим началом, если только некоторые из элементов немного больше стандартного элемента.

// You will need to put this Utility class into a code file including various
// libraries, I found that I needed at least System, Linq, Android.Views and 
// Android.Widget.
using System;
using System.Linq;
using Android.Views;
using Android.Widget;

namespace UtilityNamespace  // whatever you like, obviously!
{
    public class Utility
    {
        public static void setListViewHeightBasedOnChildren (ListView listView)
        {
            if (listView.Adapter == null) {
                // pre-condition
                return;
            }

            int totalHeight = listView.PaddingTop + listView.PaddingBottom;
            for (int i = 0; i < listView.Count; i++) {
                View listItem = listView.Adapter.GetView (i, null, listView);
                if (listItem.GetType () == typeof(ViewGroup)) {
                    listItem.LayoutParameters = new LinearLayout.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
                }
                listItem.Measure (0, 0);
                totalHeight += listItem.MeasuredHeight;
            }

            listView.LayoutParameters.Height = totalHeight + (listView.DividerHeight * (listView.Count - 1));
        }
    }
}

Спасибо @DougW, это помогло мне выбраться из затруднительного положения, когда мне пришлось работать с OtherPeople'sCode. :-)

person Phil Ryan    schedule 09.07.2014
comment
Один вопрос: когда вы вызвали метод setListViewHeightBasedOnChildren()? Потому что у меня это не всегда работает. - person Alexandre D.; 09.07.2014
comment
@AlexandreD вы вызываете Utility.setListViewHeightBasedOnChildren (yourListView), когда вы создали список элементов. т.е. убедитесь, что вы сначала создали свой список! Я обнаружил, что составляю список и даже показываю свои элементы в Console.WriteLine ... но каким-то образом элементы находились в неправильной области. Как только я понял это и убедился, что у меня есть подходящая область для моего списка, это сработало как шарм. - person Phil Ryan; 10.07.2014
comment
Дело в том, что мои списки создаются в моей ViewModel. Как я могу дождаться создания моих списков в моем представлении перед любым вызовом Utility.setListViewHeightBasedOnChildren (yourListView)? - person Alexandre D.; 10.07.2014

Раньше это было невозможно. Но с выпуском новых библиотек Appcompat и библиотек дизайна это может быть достигнуто.

Вам просто нужно использовать NestedScrollView https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html.

Я не знаю, будет ли он работать со Listview или нет, но работает с RecyclerView.

Фрагмент кода:

<android.support.v4.widget.NestedScrollView 
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

</android.support.v4.widget.NestedScrollView>
person Shashank Kapsime    schedule 10.10.2017
comment
Круто, я не пробовал, поэтому не могу подтвердить, что внутренний ListView не разрушается, но похоже, что это могло быть намерением. Глубоко опечален, что не увидел Ромена Гая в списке обвинений;) - person DougW; 12.10.2017
comment
Это работает с recyclerView, но не с listView. Спасибо - person IgniteCoders; 15.11.2017

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

db = new dbhelper(this);

 cursor = db.dbCursor();
int count = cursor.getCount();
if (count > 0)
{    
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layoutId);
startManagingCursor(YOUR_CURSOR);

YOUR_ADAPTER(**or SimpleCursorAdapter **) adapter = new YOUR_ADAPTER(this,
    R.layout.itemLayout, cursor, arrayOrWhatever, R.id.textViewId,
    this.getApplication());

int i;
for (i = 0; i < count; i++){
  View listItem = adapter.getView(i,null,null);
  linearLayout.addView(listItem);
   }
}

Примечание: если вы используете это, notifyDataSetChanged(); не будет работать должным образом, так как представления не будут перерисованы. Сделайте это, если вам нужно обойти

adapter.registerDataSetObserver(new DataSetObserver() {

            @Override
            public void onChanged() {
                super.onChanged();
                removeAndRedrawViews();

            }

        });
person PSchuette    schedule 11.05.2012

При использовании ListView внутри ScrollView возникают две проблемы.

1- ListView должен полностью расширяться до высоты своих дочерних элементов. этот ListView разрешает это:

public class ListViewExpanded extends ListView
{
    public ListViewExpanded(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        setDividerHeight(0);
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST));
    }
}

Высота разделителя должна быть равна 0, вместо этого используйте отступы в строках.

2- ListView потребляет сенсорные события, поэтому ScrollView нельзя прокручивать как обычно. Этот ScrollView решает эту проблему:

public class ScrollViewInterceptor extends ScrollView
{
    float startY;

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e)
    {
        onTouchEvent(e);
        if (e.getAction() == MotionEvent.ACTION_DOWN) startY = e.getY();
        return (e.getAction() == MotionEvent.ACTION_MOVE) && (Math.abs(startY - e.getY()) > 50);
    }
}

Это лучший способ, который я нашел!

person Ali    schedule 31.03.2014

Я использую решение, чтобы добавить все содержимое ScrollView (то, что должно быть выше и ниже listView) как headerView и footerView в ListView.

Таким образом, это работает так, как и convertview возобновляется, как и должно быть.

person brokedid    schedule 24.07.2015

благодаря коду Виная вот мой код, когда у вас нет представления списка внутри прокрутки, но вам нужно что-то вроде этого

LayoutInflater li = LayoutInflater.from(this);

                RelativeLayout parent = (RelativeLayout) this.findViewById(R.id.relativeLayoutCliente);

                int recent = 0;

                for(Contatto contatto : contatti)
                {
                    View inflated_layout = li.inflate(R.layout.header_listview_contatti, layout, false);


                    inflated_layout.setId(contatto.getId());
                    ((TextView)inflated_layout.findViewById(R.id.textViewDescrizione)).setText(contatto.getDescrizione());
                    ((TextView)inflated_layout.findViewById(R.id.textViewIndirizzo)).setText(contatto.getIndirizzo());
                    ((TextView)inflated_layout.findViewById(R.id.textViewTelefono)).setText(contatto.getTelefono());
                    ((TextView)inflated_layout.findViewById(R.id.textViewMobile)).setText(contatto.getMobile());
                    ((TextView)inflated_layout.findViewById(R.id.textViewFax)).setText(contatto.getFax());
                    ((TextView)inflated_layout.findViewById(R.id.textViewEmail)).setText(contatto.getEmail());



                    RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);

                    if (recent == 0)
                    {
                        relativeParams.addRule(RelativeLayout.BELOW, R.id.headerListViewContatti);
                    }
                    else
                    {
                        relativeParams.addRule(RelativeLayout.BELOW, recent);
                    }
                    recent = inflated_layout.getId();

                    inflated_layout.setLayoutParams(relativeParams);
                    //inflated_layout.setLayoutParams( new RelativeLayout.LayoutParams(source));

                    parent.addView(inflated_layout);
                }

relativeLayout остается внутри ScrollView, поэтому все становится прокручиваемым :)

person max4ever    schedule 22.06.2012

Вот небольшая модификация @djunod ответьте, что мне нужно, чтобы он работал безупречно:

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

    int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
    int totalHeight = 0;
    View view = null;
    for(int i = 0; i < listAdapter.getCount(); i++)
    {
        view = listAdapter.getView(i, view, listView);
        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();
}
person Eng.Fouad    schedule 23.09.2013
comment
: Привет, ваш ответ работает большую часть времени, но он не работает, если в представлении списка есть вид заголовка и вид ног. Не могли бы вы это проверить? - person hguser; 20.11.2013
comment
Мне нужно решение, когда элементы списка имеют переменные размеры, то есть какое-то текстовое представление, которое расширяется на несколько строк. Любое предложение? - person Khobaib; 26.04.2014

попробуйте, это работает для меня, я забыл, где я его нашел, где-то в переполнении стека, я здесь не для того, чтобы объяснять, почему это не работает, но это ответ :).

    final ListView AturIsiPulsaDataIsiPulsa = (ListView) findViewById(R.id.listAturIsiPulsaDataIsiPulsa);
    AturIsiPulsaDataIsiPulsa.setOnTouchListener(new ListView.OnTouchListener() 
    {
        @Override
        public boolean onTouch(View v, MotionEvent event) 
        {
            int action = event.getAction();
            switch (action) 
            {
                case MotionEvent.ACTION_DOWN:
                // Disallow ScrollView to intercept touch events.
                v.getParent().requestDisallowInterceptTouchEvent(true);
                break;

                case MotionEvent.ACTION_UP:
                // Allow ScrollView to intercept touch events.
                v.getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }

            // Handle ListView touch events.
            v.onTouchEvent(event);
            return true;
        }
    });
    AturIsiPulsaDataIsiPulsa.setClickable(true);
    AturIsiPulsaDataIsiPulsa.setAdapter(AturIsiPulsaDataIsiPulsaAdapter);

РЕДАКТИРОВАТЬ !, я наконец узнал, где я взял код. здесь ! : ListView внутри ScrollView не прокручивается на Android

person Bhimbim    schedule 03.03.2014
comment
Здесь рассказывается, как предотвратить потерю взаимодействия с просмотром прокрутки, но вопрос был о поддержании высоты просмотра списка. - person Abandoned Cart; 25.08.2014

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

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListAdapter;

public class StretchedListView extends LinearLayout {

private final DataSetObserver dataSetObserver;
private ListAdapter adapter;
private OnItemClickListener onItemClickListener;

public StretchedListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setOrientation(LinearLayout.VERTICAL);
    this.dataSetObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            syncDataFromAdapter();
            super.onChanged();
        }

        @Override
        public void onInvalidated() {
            syncDataFromAdapter();
            super.onInvalidated();
        }
    };
}

public void setAdapter(ListAdapter adapter) {
    ensureDataSetObserverIsUnregistered();

    this.adapter = adapter;
    if (this.adapter != null) {
        this.adapter.registerDataSetObserver(dataSetObserver);
    }
    syncDataFromAdapter();
}

protected void ensureDataSetObserverIsUnregistered() {
    if (this.adapter != null) {
        this.adapter.unregisterDataSetObserver(dataSetObserver);
    }
}

public Object getItemAtPosition(int position) {
    return adapter != null ? adapter.getItem(position) : null;
}

public void setSelection(int i) {
    getChildAt(i).setSelected(true);
}

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
    this.onItemClickListener = onItemClickListener;
}

public ListAdapter getAdapter() {
    return adapter;
}

public int getCount() {
    return adapter != null ? adapter.getCount() : 0;
}

private void syncDataFromAdapter() {
    removeAllViews();
    if (adapter != null) {
        int count = adapter.getCount();
        for (int i = 0; i < count; i++) {
            View view = adapter.getView(i, null, this);
            boolean enabled = adapter.isEnabled(i);
            if (enabled) {
                final int position = i;
                final long id = adapter.getItemId(position);
                view.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        if (onItemClickListener != null) {
                            onItemClickListener.onItemClick(null, v, position, id);
                        }
                    }
                });
            }
            addView(view);

        }
    }
}
}
person Alécio Carvalho    schedule 19.02.2014

Все эти ответы неверны !!! Если вы пытаетесь поместить представление списка в представление прокрутки, вам следует переосмыслить свой дизайн. Вы пытаетесь поместить ScrollView в ScrollView. Вмешательство в список повредит его производительности. Это было разработано для Android.

Если вы действительно хотите, чтобы список находился в той же полосе прокрутки, что и другие элементы, все, что вам нужно сделать, это добавить другие элементы в начало списка с помощью простого оператора switch в вашем адаптере:

class MyAdapter extends ArrayAdapter{

    public MyAdapter(Context context, int resource, List objects) {
        super(context, resource, objects);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
         ViewItem viewType = getItem(position);

        switch(viewType.type){
            case TEXTVIEW:
                convertView = layouteInflater.inflate(R.layout.textView1, parent, false);

                break;
            case LISTITEM:
                convertView = layouteInflater.inflate(R.layout.listItem, parent, false);

                break;            }


        return convertView;
    }


}

Адаптер списка может обрабатывать все, поскольку он отображает только то, что видно.

person TacoEater    schedule 10.02.2016

Вся эта проблема исчезла бы, если бы LinearLayout имел метод setAdapter, потому что тогда, когда вы сказали кому-то использовать его вместо этого, альтернатива была бы тривиальной.

Если вам действительно нужен прокручиваемый ListView внутри другого прокручиваемого представления, это не поможет, но в противном случае это, по крайней мере, даст вам представление.

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

У меня нет под рукой образца кода, но если вы хотите что-то вроде.

<ListView/>

(other content)

<ListView/>

Затем вам нужно создать адаптер, представляющий весь этот контент. ListView / Adapters достаточно умен, чтобы работать с разными типами, но вам нужно написать адаптер самостоятельно.

API пользовательского интерфейса Android не так развит, как почти все остальное, поэтому у него нет тех же тонкостей, что и на других платформах. Кроме того, когда вы делаете что-то на Android, вам нужно быть в мышлении Android (unix), где вы ожидаете, что для выполнения чего-либо вам, вероятно, придется собрать функциональность из более мелких частей и написать кучу собственного кода, чтобы получить это Работа.

person majinnaibu    schedule 13.01.2013

Когда мы помещаем ListView внутрь ScrollView, возникают две проблемы. Один из них ScrollView измеряет своих дочерних элементов в НЕПРЕДВИДЕННОМ режиме, поэтому ListView устанавливает собственную высоту для размещения только одного элемента (я не знаю почему), другой ScrollView перехватывает событие касания, поэтому ListView не прокручивается.

Но мы можем поместить ListView внутрь ScrollView с помощью некоторого обходного пути. В этом сообщении я объясняю обходной путь . С помощью этого обходного пути мы также можем сохранить функцию повторного использования ListView.

person Durgadass S    schedule 24.10.2014

Вместо того, чтобы помещать представление списка внутри Scrollview, поместите остальную часть содержимого между представлением списка и открытием Scrollview как отдельного представления и установите это представление в качестве заголовка представления списка. Таким образом, вы в конечном итоге останетесь только в виде списка, отвечающего за прокрутку.

person Saksham    schedule 14.03.2016

Эта библиотека является самым простым и быстрым решением проблемы.

person Kashif Nazar    schedule 25.01.2017

Никогда не используйте listview внутри scrollview. Вместо этого вы должны использовать NestedScrollView в качестве родителя и RecyclerView внутри этого .... поскольку он обрабатывает множество проблем с прокруткой.

person Zohab Ali    schedule 31.01.2021

Вот моя версия кода, который вычисляет общую высоту представления списка. Это работает для меня:

   public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null || listAdapter.getCount() < 2) {
        // pre-condition
        return;
    }

    int totalHeight = 0;
    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(BCTDApp.getDisplaySize().width, View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

    for (int i = 0; i < listAdapter.getCount(); i++) {
        View listItem = listAdapter.getView(i, null, listView);
        if (listItem instanceof ViewGroup) listItem.setLayoutParams(lp);
        listItem.measure(widthMeasureSpec, heightMeasureSpec);
        totalHeight += listItem.getMeasuredHeight();
    }

    totalHeight += listView.getPaddingTop() + listView.getPaddingBottom();
    totalHeight += (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight;
    listView.setLayoutParams(params);
    listView.requestLayout();
}
person myforums    schedule 13.02.2014