我正试图找到一种方法来根据子项的高度设置列表视图的高度。我按照这里给出的解决方案: How can I put a ListView into a ScrollView without it collapsing?
public 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);
if(listItem != null){
listItem.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
listItem.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
//listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
现在我在listview上调用上面的函数:
public void displayReviews(ArrayList<Reviews> resultReviews){
// Hide the loading progress
hideReviewsLoading();
if(resultReviews != null && resultReviews.size() > 0){
mCurrentReviewList.onFetchFinished(resultReviews);
setListViewHeightBasedOnChildren(mCurrentReviewList.getListView());
}
else{
// Display a generic text to indicate no reviews are in yet
displayEmptyText();
}
}
上面的mCurrentreviewList是一个ListFragment,它基本上有一个适配器来设置布局中的元素。
我遇到的问题是它测量的每个列表项的高度都不准确。最后,当所有列表项(评论)填充包含它的整体列表视图时,永远不会完全显示所有列表项。它切断了下面的某个地方 - 就像只显示总共10个中的7.5个评论一样。
我不确定我做错了什么。任何帮助和方向将不胜感激!
答案 0 :(得分:31)
好的,好像我能够弄清楚测量结果不准确的原因。我试图通过传递
来测量列表视图的高度listItem.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
对于具有可变/动态高度的ListItem,这将无法解决。测量必须知道至少一个变量,在这种情况下,它将是恒定宽度。因此,首先使用:
计算您知道将保持不变的列表视图的所需宽度int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
然后将其传递给listitem度量。完整代码如下:
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
if(listItem != null){
// This next line is needed before you call measure or else you won't get measured height at all. The listitem needs to be drawn first to know the height.
listItem.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
listItem.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
totalHeight += listItem.getMeasuredHeight();
}
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
请注意 这是一种严厉的实施方式,并不是推荐的方式。在执行此操作之前,请参阅How can I put a ListView into a ScrollView without it collapsing?并准确了解您的操作。
答案 1 :(得分:1)
ListView应该滚动 - 所以理论上你可以拥有无限数量的项目。无需根据ListView中的项目数设置ListView的长度。
如果确实需要设置长度,那么就会失去使用ListView的目的。请使用其他视图,例如Vertical ScrollView或其他所需的视图。
答案 2 :(得分:0)
我没有足够的声誉来发表评论但是关于falc0nit3的回答,我已经实现了这一点,但最终遇到了内存错误,其中大型单元格有图像等。
这是因为for循环的第一行View listItem = listAdapter.getView(i, null, listView);
。
传入null作为convertView参数将导致适配器膨胀列表中的每一行。这并不理想,所以相反传入一个已经膨胀的行,以便getView只需要替换该行内的内容(例如,自己给列表的第一行充气并继续使用它)。请参阅以下链接http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
中的“查看回收”答案 3 :(得分:0)
falc0nit3的答案(已接受的答案)适用于我,但如果您使用列表分隔符
totalHeight += listView.getDividerHeight() * i;
所以最终的代码片段如下所示:
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
int i;
for (i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0)
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
//add divider height to total height as many items as there are in listview
totalHeight += listView.getDividerHeight()*i;
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}