Строки Android ListView в ScrollView отображаются не полностью - обрезаны

Я столкнулся с проблемой при встраивании ListView в ScrollView или, по крайней мере, там, где, я полагаю, возникла проблема. Элемент ListView довольно прост:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/general_background_list_middle" 
    android:paddingTop="4dp"
    android:paddingBottom="4dp"
    android:paddingRight="0dp"
    android:paddingLeft="0dp">

    <ImageView
        android:id="@+id/chat_friends_avatar"       
        android:layout_width="45dp"
        android:layout_height="45dp"
        android:layout_marginLeft="7dp"
        android:layout_marginRight="8dp"
        android:paddingRight="0dp" 
        android:paddingLeft="0dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/friends_icon_avatar_default"/>

    <TextView
        android:id="@+id/chat_message_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/chat_friends_avatar"
        android:layout_alignParentTop="true"
        android:layout_marginRight="35dp"
        android:maxLines="10"
        android:textSize="12dp"/>

    <TextView
        android:id="@+id/chat_friend_name"
        android:layout_width="140dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="3dp"
        style="@style/SubText"
        android:layout_toRightOf="@id/chat_friends_avatar"      
        android:layout_below="@id/chat_message_text" />

    <TextView
        android:id="@+id/chat_message_time"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:layout_marginRight="8dp"
        android:layout_marginTop="3dp"
        style="@style/SubText"
        android:layout_alignParentRight="true"
        android:layout_below="@id/chat_message_text" />

</RelativeLayout>   

Однако, когда я встраиваю список таких элементов в ScrollView, между некоторыми другими элементами строки отображаются не полностью, они обрезаются (см. Изображение ниже), если текст переносится. ListView создается следующим образом в ScrollView:

<ListView
android:id="@+id/info_chat_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:cacheColorHint="@color/frame_background_color"
android:clickable="false"
android:divider="@null"
android:footerDividersEnabled="false"
android:focusable="false" >
</ListView> 

Если высота ListView установлена на «wrap_content» показан только первый элемент. Вот почему я использую метод для вычисления высоты строк списка:

private int getCommentsListHeight() {
        if (mChatAdapter != null && mChatAdapter.getCount() != 0) {
            if (mChatList != null) {// && mCommentsListItemHeight == 0) {
                mCommentsListItemHeight = 0;
                for (int i = 0; i < mChatAdapter.getCount(); i++) {
                    // Get view item height
                    View viewItem = mChatAdapter
                            .getView(i, new View(OnAirActivity.this), mChatList);
                    viewItem.measure(0, 0);
                    Logger.d(LOGTAG, "View " + i + " measured height = " + viewItem.getMeasuredHeight());
                    mCommentsListItemHeight += viewItem.getMeasuredHeight();
                }
            }
            //return mChatAdapter.getCount() * mCommentsListItemHeight;
            return mCommentsListItemHeight;
        } else {
            return 0;
        }
    }

К сожалению, в случае, когда текст внутри TextView переносится даже на несколько строк, высота элемента строки, возвращаемого методом getMeasuredHeight (), является постоянной. Также getLineCount (), вызываемый для TextView внутри элемента строки, возвращает 1, даже если текст переносится.

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

Есть ли у вас какие-либо предложения относительно того, что может быть здесь не так? Мне действительно не нравится идея ручного измерения высоты элементов списка, и она, очевидно, не работает, но почему андроид не может красиво растянуть ListView внутри ScrollView, чтобы вместить все это туда?

Обрезанный список: see image

Ответы на вопрос(9)

Решение Вопроса

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

 PawelPredki22 мая 2012 г., 22:33
Спасибо за быстрый ответ. Таким образом, вы предлагаете, например, программно создавать экземпляры этих представлений строк внутри Scrollview один за другим?
 22 мая 2012 г., 23:41
тогда, возможно, я бы предложил вам использовать верхние и / или нижние колонтитулы ListView для установки всех других представлений, которые у вас есть в данный момент внутри ScrollView.
 PawelPredki23 мая 2012 г., 00:03
Это немного излишне, так как большинство элементов в используемом в настоящее время ScrollView НЕ являются проблемным списком ... Я понимаю, что нет способа заставить ListView нормально работать внутри ScrollView, поэтому мне нужно подумать о том, какие Обходной путь / решение является лучшим в моем случае. Спасибо за помощь!
 22 мая 2012 г., 22:50
Нет. Вы должны использовать ListView, но не помещайте его в ScrollView. Вы можете настроить элементы строки, переопределивgetView метод из адаптера, используемый для ListView
 PawelPredki22 мая 2012 г., 23:30
Я использую адаптер, и это отлично работает в других действиях, которые я упомянул, где ListView находится в пределах LinearLayout. Я должен использовать ScrollView здесь, так как моя активность содержит много элементов, которые не помещаются на экране, включая чат ListView, который является источником всех проблем ...

Это работает для меня

<RelativeLayout                                          xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:padding="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/tv_status"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="17sp"
        android:text="@string/text_list_devices" />

    <ListView
        android:id="@+id/lv_paired"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:cacheColorHint="#00000000"
        android:layout_above="@+id/signup_t"
        android:layout_below="@id/tv_status"
        />

    <Button

        android:id="@+id/signup_t"
        style="?android:textAppearanceSmall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:textColor="@android:color/white"
        android:layout_alignParentBottom="true"
        android:text="Print All Records"
        android:typeface="sans"
        android:layout_marginLeft="45dp"
        android:layout_marginRight="45dp"
        android:textSize="24sp"
        android:background="@drawable/selector_for_button"
        android:textStyle="bold" />
</RelativeLayout>

Я принял рекомендацию не использовать элемент ListView внутри ScrollView для сердца и решил использовать метод грубой силы, чтобы добиться того, что мне нужно. Поскольку существует постоянное число до пяти строк списка, которые необходимо отобразить, я удалил экземпляр ListView из файла xml и заменил его пятью экземплярами строк:

<include android:id="@+id/info_comment_1" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_2" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_3" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_4" layout="@layout/chat_single_message" />
<include android:id="@+id/info_comment_5" layout="@layout/chat_single_message" />

В классе Activity я объявляю пять заполнителей для этих представлений:

private RelativeLayout mChatMessages[] = new RelativeLayout[COMMENTS_NUMBER];

и инициализировать их с помощью:

mChatMessages[0] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_1);
mChatMessages[1] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_2);
mChatMessages[2] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_3);
mChatMessages[3] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_4);
mChatMessages[4] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_5);

Затем, всякий раз, когда получено новое сообщение, я использую ChatAdapter (то же самое, что я использовал для ListView ранее) и вызываю его метод getView ():

protected void updateChatMessages() {
  int msgCount = mChatAdapter.getCount();
  for (int i = 0; i < COMMENTS_NUMBER; i++) {
    if (msgCount <= i) {
      mChatMessages[i].setVisibility(View.GONE);
    } else {
      mChatMessages[i] = (RelativeLayout) mChatAdapter.getView(i, mChatMessages[i], null); 
      mChatMessages[i].setVisibility(View.VISIBLE);
    }   
  }
}

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

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

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

У меня была похожая проблема. у меня есть

RelativeLayout
  listView
  includeLayout  

где я включаю некоторую нижнюю навигацию под listView с этим

<include
    android:id="@+id/includeLayout"
    layout="@layout/bottom_nav_bar"

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

android:layout_alignBottom="@+id/includeLayout"

в мой список. Это, казалось, тянуло listView вниз к верхней части нижней навигационной панели, так что listView теперь использует всю доступную высоту (и прокручивается по мере необходимости).

У меня была такая же проблема в моем проекте. Вам нужно создатьsimple LinearLayout inside ScrollView, После этого вам нужно создатьnew View сyour listview item xml с помощьюLayoutInflater, После создания поместите все данные вnew View and add to LinearLayout as child view:

linearLayot.addView(newView, position_you_need).

Надеюсь, это поможет вам!

 24 мая 2012 г., 05:35
Нет, я предлагаю вам сделать следующее: & lt; ScrollView & gt; & Lt; LinearLayout & GT; & lt; ... мои другие взгляды ... & gt; & Lt; & LinearLayout GT; & Lt; / LinearLayout & GT; & Lt; / Scrollview & GT ;. Основная идея состоит в том, чтобы поместить элементы списка в линейный макет, а не в специальный макет списка. Все элементы будут прокручиваться и показываться без отсечения.
 PawelPredki23 мая 2012 г., 12:32
Таким образом, вы предлагаете расположить макеты в следующем порядке:<ScrollView> <LinearLayout> <... my other views ...> <LinearLayout> <ProblematicListView> </LinearLayout> <... more views ...> </LinearLayout> </ScrollView>  Разве это не то же самое? ListView все еще находится внутри ScrollView? Прямо сейчас я пошел за «руководство» путем включения & lt; включите android: id = & quot; @ + id / chat_comment_x & quot; layout = & quot; mylayout & quot; & gt ;, x = 0..5 И у меня есть массив заполнителей для этих пяти макетов, которые я заполняю с помощью того же адаптера, который использовал для представления списка. По сути, у меня есть динамический список из 5 элементов, и он отлично работает.

попытайся.. после создания всех представлений добавьте нижнюю линию для местоположения ScrollView на экране (x, y)

  ScrollView scrollView = (ScrollView)findViewById(R.id.scrollView);

  scrollView.smoothScrollTo(0,0);// top location zero index

Используйте этот метод, созданныйhttps://stackoverflow.com/users/205192/dougw

 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);
    }
 09 мар. 2015 г., 23:31
Этот ответ скопирован почти дословно отсюда:stackoverflow.com/a/3495908/1221537
 21 июл. 2014 г., 10:56
params.height - это конечная высота, которая установлена. Вы можете добавить фиксированный буфер на случай, если вам придется продолжать заполнять
 19 июл. 2014 г., 23:35
Это работает нормально, но затем, когда я добавил отступы вокруг списка, чтобы убрать текст с края экрана, небольшой фрагмент снова обрезается. Что я должен добавить, чтобы это исправить?
 07 февр. 2014 г., 16:14
Это работает для меня, но у меня нет проблемы переноса текста, как это было в оригинальном вопросе. Спасибо!
 17 янв. 2015 г., 08:07
Как реализовать загрузку большего количества данных?

Here resource of main layout with ScrollView:

<ScrollView android:layout_height="fill_parent" android:layout_width="fill_parent">
<LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/parentLayout"/>
</ScrollView>

Here the code to insert items:

parentLayout.removeAllViews();
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = comments.size() - 1; i >= 0; i--) {
CommentInfo comment = comments.get(i);
View view = inflater.inflate(your_resource_id, null, false);

TextView commentsContent =(TextView)view.findViewById(R.id.commentContent);
if (commentsContent != null) {
    String data = String.format("%s (by %s, %s)",  comment.getCommentText(), comment.getUserName(),
        commentsContent.setTextSize(st.getTextSize());
    commentsContent.setText(data);

}

parentLayout.addView(view, 0);

}       
 24 мая 2012 г., 18:23
Добавьте верхний макет, например LinearLayout, в качестве дочернего ScrollView и добавьте в него дочерний макет любых других элементов управления, включая LinearLayout, которые будут использоваться в качестве контейнера списка. Я делаю то же самое, это работает правильно.
 07 янв. 2015 г., 10:32
Что, если требуется ExpandableListView вместо ListView?
 PawelPredki24 мая 2012 г., 14:39
Если у вас есть другие дочерние элементы внутри ScrollView, кроме LinearLayout, то это противоречит тому, что Android советует вам сделать здесь:developer.android.com/reference/android/widget/ScrollView.html  & quot; ScrollView - это FrameLayout, то есть вы должны поместить в него одного потомка, содержащего все содержимое для прокрутки; этот дочерний элемент сам может быть менеджером компоновки со сложной иерархией объектов & quot;
 PawelPredki24 мая 2012 г., 09:33
Это было бы хорошим решением, если бы единственными элементами в моем ScrollView были представления комментариев. И в этом случае размещение ListView внутри LinearLayout будет лучшим решением. В моем случае, в LinearLayout внутри ScrollView гораздо больше элементов, поэтому мне сначала нужно знать, куда поместить комментарии. Я думаю, что оба подхода в порядке.

Я вижу, что ListView находится внутри ViewPager; Еще один простой подход к решению этой проблемы заключается в добавлении app:layout_behavior="@string/appbar_scrolling_view_behavior" на ViewPager в вашем макете XML, как показано ниже.

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

Чтобы предотвратить такое же поведение внизу списка, вы также можете добавитьandroid:layout_marginBottom="?attr/actionBarSize" на ViewPager вроде так

<android.support.v4.view.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:layout_marginBottom="?attr/actionBarSize"/>

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

Ваш ответ на вопрос