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, даже если текст обернут.

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

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

обрезается список: see image

9 ответов


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


используйте этот метод, созданный 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);
    }

вот ресурс основного макета с 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>

здесь код для вставки элементов:

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);

}       

У меня была та же проблема в моем проекте.Вам нужно создать простой LinearLayout внутри ScrollView. После этого вам нужно создать новый вид С ваш элемент listview xml используя LayoutInflater. После создания поместите все данные в новый вид и добавить в LinearLayout как дочерний вид:

linearLayot.addView(newView, position_you_need).

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


Я принял рекомендацию не использовать элемент 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 может хорошо соответствовать им, и ничего не обрезается.

для динамического числа строк подход, предложенный Лайко, может быть использован с представлениями, созданными программно и добавленными в 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"/>

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


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

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

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

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

RelativeLayout
  listView
  includeLayout  

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

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

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

android:layout_alignBottom="@+id/includeLayout"

в мой listView. Это, казалось, тянет listView вниз к верхней части нижней навигации, так что 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>