ScrollView 中的 Android ListView 行未完全显示 - 已剪辑
Posted
技术标签:
【中文标题】ScrollView 中的 Android ListView 行未完全显示 - 已剪辑【英文标题】:Android ListView rows in ScrollView not fully displayed - clipped 【发布时间】:2012-05-29 09:06:44 【问题描述】:我在 ScrollView 中嵌入 ListView 时遇到了问题,或者至少我猜这就是问题所在。 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_
android:layout_
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_
android:layout_
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_
android:layout_
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_
android:layout_
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_
android:layout_
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_
android:layout_
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() 方法返回的行元素的高度也是恒定的。即使文本被换行,在行元素内的 TextView 上调用的 getLineCount() 也会返回 1。
另一方面,如果此 ListView 嵌入在 LinearLayout 中,则一切正常,并且完整列表显示没有剪辑。
您对这里可能出现的问题有什么建议吗?我真的不喜欢手动测量列表元素高度的想法,而且它显然不起作用,但为什么 android 不能很好地拉伸 ScrollView 内的 ListView 以适应它呢?
剪辑列表:
【问题讨论】:
【参考方案1】:使用https://***.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);
【讨论】:
这对我有用,但我没有像原来的问题那样包装文本的问题。谢谢! 这很好用,但是当我在列表视图周围添加填充以将文本从屏幕边缘移开时,又会剪掉一小部分。我应该添加什么来解决这个问题? params.height 是设置的最终高度。您可以添加一个固定缓冲区以防您必须保持填充 如何实现加载更多数据? 这个答案几乎是从这里逐字复制的:***.com/a/3495908/1221537【参考方案2】:将ListView
封装在ScrollView
中是一种不好的做法,因为 ListView 本身包含滚动功能。您应该实现一个不包含这种视图层次结构的解决方案,我希望它能发挥作用:)
【讨论】:
感谢您的快速回答。因此,您的建议是,例如,以编程方式在 Scrollview 内逐一实例化这些行视图? 没有。您应该使用 ListView 但不要将其放在 ScrollView 中。您可以通过覆盖用于 ListView 的适配器的 getView 方法来自定义行项 我正在使用适配器,这在我提到的 ListView 在 LinearLayout 中的其他活动中工作正常。我必须在这里使用 ScrollView,因为我的 Activity 包含许多不适合屏幕的元素,包括聊天 ListView,它是所有问题的根源...... 那么也许我会建议您使用 ListView 的页眉和/或页脚来设置您目前在 ScrollView 中拥有的所有其他视图。 这有点矫枉过正,因为当前使用的 ScrollView 中的大多数元素都不是麻烦的列表...我知道没有办法让 ListView 在ScrollView 所以我需要考虑哪种解决方法/解决方案在我的情况下是最好的。感谢您的帮助!【参考方案3】:这里是带有 ScrollView 的主布局资源:
<ScrollView android:layout_ android:layout_>
<LinearLayout android:orientation="vertical" android:layout_ android:layout_ 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);
【讨论】:
如果我的 ScrollView 中唯一的元素是 cmets 视图,这将是一个很好的解决方案。在这种情况下,将 ListView 放入 LinearLayout 将是最好的解决方案。就我而言,ScrollView 内的 LinearLayout 中有更多元素,所以我首先需要知道将 cmets 放在哪里。我想这两种方法都很好。 在 LinearLayout 之后和之前将任何元素添加到 ScrollView 中没有问题。我只是剪切了一些代码以显示您的确切需求。在实际文件中,我在 LinearLaout 之前和之后包含一个也用作 ListView 的 LinearLayout 之后有许多控件。 如果您在 ScrollView 中除了 LinearLayout 之外还有其他子元素,那么这与 Android 在这里告诉您的做法相反:developer.android.com/reference/android/widget/ScrollView.html“ScrollView 是 FrameLayout,这意味着您应该将一个子元素放入它包含要滚动的全部内容;这个孩子本身可能是一个具有复杂对象层次结构的布局管理器" 添加顶部布局,例如 LinearLayout 作为 ScrollView 子布局,并向其添加任何其他控件,包括用作列表容器的 LinearLayouts。我做同样的事情,它工作正常。 如果需要 ExpandableListView 而不是 ListView 怎么办?【参考方案4】:我在我的项目中遇到了同样的问题。您需要在 ScrollView 中创建 简单的 LinearLayout。之后,您需要使用 LayoutInflater 创建带有 您的列表视图项 xml 的 new View。创建后将所有数据放入新视图并作为子视图添加到LinearLayout:
linearLayot.addView(newView, position_you_need).
希望对你有帮助!
【讨论】:
所以您建议按以下顺序排列布局:<ScrollView> <LinearLayout> <... my other views ...> <LinearLayout> <ProblematicListView> </LinearLayout> <... more views ...> </LinearLayout> </ScrollView>
这不是差不多吗? ListView 还在 ScrollView 里面吗?现在,我通过执行 我接受了不要在 ScrollView 中使用 ListView 元素的建议,并决定使用稍微蛮力的方法来实现我所需要的。由于需要显示的列表行数是恒定的,因此我从 xml 文件中删除了 ListView 实例,并将其替换为五个行实例:
<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 建议的方法可以用于以编程方式实例化视图并添加到 ScrollView 内的 LinearLayout。
【讨论】:
【参考方案6】:我可以看到 ListView 在 ViewPager 中;解决此问题的另一种简单方法是添加
app:layout_behavior="@string/appbar_scrolling_view_behavior"
到您的布局 xml 中的 ViewPager,如下所示。
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_
android:layout_
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_
android:layout_
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_marginBottom="?attr/actionBarSize"/>
这来晚了,但我希望它可以帮助任何其他人。
【讨论】:
【参考方案7】:试试看.. 创建所有视图后,为屏幕上的 ScrollView 位置添加波纹管 (x,y)
ScrollView scrollView = (ScrollView)findViewById(R.id.scrollView);
scrollView.smoothScrollTo(0,0);// top location zero index
【讨论】:
【参考方案8】:我遇到了类似的问题。我有一个
RelativeLayout
listView
includeLayout
我在列表视图下方包含一些底部导航
<include
android:id="@+id/includeLayout"
layout="@layout/bottom_nav_bar"
并且我的 listView 被剪裁了 - 没有占用标题和底部导航之间可用的全部高度。我尝试了此线程和其他线程中建议的各种 xml 设置,但对我有用的是添加
android:layout_alignBottom="@+id/includeLayout"
到我的列表视图。这似乎将 listView 拉到底部导航的顶部,因此 listView 现在正在使用完整的可用高度(并根据需要滚动)。
【讨论】:
【参考方案9】:这对我有用
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:padding="@dimen/activity_vertical_margin">
<TextView
android:id="@+id/tv_status"
android:layout_
android:layout_
android:gravity="center"
android:textSize="17sp"
android:text="@string/text_list_devices" />
<ListView
android:id="@+id/lv_paired"
android:layout_
android:layout_
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_
android:layout_
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>
【讨论】:
【参考方案10】:这是不好的做法。但是有一些我们无法避免使用它的情况。例如动态电子商务布局,我们可能会放置多个列表或回收视图,但您不想在单个项目高度内滚动(如果不小心想要!!)。我遇到了这种问题。我用一种简单的方法修复了。我不说这是正确的方法,但它可能会有所帮助。 !!我曾经回收视图。
(01) 创建一个接口返回视图高度。
public interface AfterViewLoadListener
void onViewHeightMeasured(int height, String mode);
(02) 与您的活动一起实施
public class *Activity extends AppCompatActivity implements AfterViewLoadListener
/** your codes **/
final SimpleListRecycleAdapter order_adapter = new SimpleListRecycleAdapter(this,"ORDER");
@Override
public void onViewHeightMeasured(int height, String mode)
if(mode.equals("ORDER") && height > 0)
recycleView.setMinimumHeight(height);
(03) 内部循环视图自定义适配器
AfterViewLoadListener viewLoadListener = null;
public SimpleListRecycleAdapter(AfterViewLoadListener listener, String mode)
if(listener instanceof AfterViewLoadListener)
viewLoadListener = listener;
this.mode = mode;
(04) 重写 onViewAttachedToWindow 方法
@Override
public void onViewAttachedToWindow(@NonNull SimpleListViewHolder holder)
super.onViewAttachedToWindow(holder);
View view = holder.itemView;
view.measure(0, 0);
this.viewMinHeight = view.getMeasuredHeight();
if(!firstFlag)
firstFlag = true;
viewLoadListener.onViewHeightMeasured(this.viewMinHeight*filtered.length(),mode);
(05) 就是这样。它对我有用。
【讨论】:
以上是关于ScrollView 中的 Android ListView 行未完全显示 - 已剪辑的主要内容,如果未能解决你的问题,请参考以下文章
Android - MPAndroidChart 中的拖动在 ScrollView 中时无响应
ScrollView Android 中的 ListFragment
ScrollView 中的 ListView 在 Android 上不滚动
Android 布局问题,一个 ScrollView 中的几个 ListView