Ответ 1
Это BAD практика для инкапсуляции ListView
в ScrollView
, потому что ListView сам содержит возможности прокрутки. Вы должны реализовать решение, которое не содержит такой иерархии представлений, и я надеюсь, что он сделает магию:)
Я столкнулся с проблемой при встраивании 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, чтобы вместить все это там?
Вырезанный список:
Это BAD практика для инкапсуляции 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);
}
У меня была такая же проблема в моем проекте. Вам нужно создать простой LinearLayout внутри ScrollView. После этого вам нужно создать новый View с помощью вашего элемента списка xml, используя LayoutInflater. После создания поместите все данные в новый View и добавьте LinearLayout в виде дочернего представления:
linearLayot.addView(newView, position_you_need).
Надеюсь, это поможет вам!
Здесь ресурс основного макета с 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);
}
Я принял рекомендацию не использовать элемент 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.
Я вижу, что 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
где я включаю некоторый нижний nav под listView с этим
<include
android:id="@+id/includeLayout"
layout="@layout/bottom_nav_bar"
и мой listView был обрезан - не имея полной высоты между заголовком и нижней навигацией. Я пробовал различные настройки xml, предложенные в этом и других потоках, но для меня работало добавить
android:layout_alignBottom="@+id/includeLayout"
в мой списокView. Похоже, что 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>