我在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_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()方法返回的row元素的高度是不变的。即使文本被包装,在row元素内的TextView上调用的getLineCount()也会返回1。
另一方面,如果此ListView嵌入在LinearLayout中,一切正常,并且显示完整列表而不会剪裁。
你对这里可能出现的问题有什么建议吗?我真的不喜欢手动测量列表元素高度的想法,它显然不起作用,但为什么android不能很好地拉伸ScrollView中的ListView以适应它的全部?
剪辑列表:
答案 0 :(得分:40)
使用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);
}
答案 1 :(得分:11)
将ListView
封装在ScrollView
中是一种 BAD 做法,因为ListView本身包含滚动功能。你应该实现一个不包含这种视图层次结构的解决方案,我希望它能发挥作用:)
答案 2 :(得分:2)
我的项目遇到了同样的问题。你需要在ScrollView中创建简单的LinearLayout 。之后,您需要使用 LayoutInflater ,使用您的列表视图项xml 创建新视图。创建后将所有数据放入新视图并添加到LinearLayout作为子视图:
linearLayot.addView(newView, position_you_need).
希望它能帮到你!
答案 3 :(得分:2)
这里是使用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);
}
答案 4 :(得分:1)
我建议不要在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。
答案 5 :(得分:0)
我可以看到ListView在ViewPager中;另一种解决此问题的简单方法是添加
app:layout_behavior="@string/appbar_scrolling_view_behavior"
到布局xml中的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"
添加到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"/>
这是迟到的,但我希望它可以帮助任何其他人。
答案 6 :(得分:0)
我有类似的问题。我有一个
RelativeLayout
listView
includeLayout
我使用此
在listView下面包含一些底部导航<include
android:id="@+id/includeLayout"
layout="@layout/bottom_nav_bar"
并且我的listView被剪裁了 - 没有在标题和底部导航之间获得完整的高度。我尝试了在这个和其他线程中建议的各种xml设置,但对我有用的是添加
android:layout_alignBottom="@+id/includeLayout"
到我的listView。这似乎将listView拉到底部导航的顶部,因此listView现在使用完整的可用高度(并根据需要滚动)。
答案 7 :(得分:0)
这对我有用
<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>
答案 8 :(得分:0)
这是错误的做法。但是在某些情况下,我们无法避免使用它们。例如动态电子商务布局,我们可能会放置多个列表或回收视图,但您不想在单个项目高度内滚动(如果不希望的话!)。我遇到了这种问题。我用一种简单的方法解决了。我没有告诉您这是正确的方法,但可能会有所帮助。 !!我曾经回收过视图。
(01)创建一个界面以返回视图高度。
const box = document.querySelector('#box');
const showButton = document.querySelector('#show-button');
showButton.addEventListener('click', showBox);
let isDisabled = false;
const isVisible = elem => !!elem && !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js
function toggleDisabled(bool) {
showButton.attributes.disabled = bool;
isDisabled = bool;
}
function toggleDisplay(display, opacity) {
document.body.style.opacity = opacity;
box.style.display = display;
}
function showBox(event) {
if (!isDisabled) {
event.preventDefault();
event.stopPropagation();
toggleDisplay("block", 0.5);
toggleDisabled(true);
document.addEventListener('click', outsideClickListener);
}
}
function outsideClickListener(event) {
if (!box.contains(event.target) && isVisible(box)) { // or use: event.target.closest(selector) === null
toggleDisplay("none", 1);
toggleDisabled(false);
document.removeEventListener('click', outsideClickListener)
}
}
(02)实现您的活动
<button id="show-button">New Audio</button>
<div id="box" style="display: none">
<button>Record Directly</button>
</div>
(03)在回收视图自定义适配器中
frameworkElement.LayoutTransform = new ScaleTransform(scale, scale);
left = (double)frameworkElement.GetValue(Canvas.LeftProperty);
top = (double)frameworkElement.GetValue(Canvas.TopProperty);
frameworkElement.SetValue(Canvas.LeftProperty, _marginSize);
frameworkElement.SetValue(Canvas.TopProperty, _marginSize);
prnt.PrintVisual(frameworkElement, $"Printing MikObject {frameworkElement.Name}");
}
catch (Exception e)
{
PresHelper.WriteToDebug(_presBaseObject, e);
}
finally
{
frameworkElement.SetValue(Canvas.LeftProperty, left);
frameworkElement.SetValue(Canvas.TopProperty, top);
frameworkElement.LayoutTransform = originalScale;
}
(04)重写onViewAttachedToWindow方法
public interface AfterViewLoadListener {
void onViewHeightMeasured(int height, String mode);
}
(05)就是这样。它对我有用。