Android 计算列表视图的大小或如何让它完全展开
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2312683/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calculate the size of a list view or how to tell it to fully expand
提问by Rudy Mutter
I am currently trying to use a ListView inside of a ScrollView. I know from what I've read that this is looked down upon, but I'm trying to get the ListView to expand completely by showing all of its rows so there is no need for it to scroll. I've been struggling, however, with how to tell the ListView to completely expand to show all of its rows since it needs a defined height. How do I calculate the height of a fully expanded ListView before it is drawn?
我目前正在尝试在 ScrollView 中使用 ListView。我从我所读到的内容中知道这被看不起,但是我试图通过显示其所有行来使 ListView 完全展开,因此无需滚动。然而,我一直在努力如何告诉 ListView 完全展开以显示它的所有行,因为它需要一个定义的高度。如何在绘制之前计算完全展开的 ListView 的高度?
This problem mainly stems from the fact that you can't put a scrollable view inside of another scrollable view. I am okay with the fact that the ListView won't be able to scroll as long as I can make it expand to show all of its rows. I cannot do this, however, without being able to give it a defined height, which it seems I would need to calculate.
这个问题主要源于这样一个事实,即您不能将可滚动视图放入另一个可滚动视图中。我对 ListView 无法滚动的事实感到满意,只要我可以让它展开以显示其所有行。然而,我无法做到这一点,无法给它一个定义的高度,这似乎是我需要计算的。
My full layout is too big for the "physical" screen and needs to scroll in order to show the rest of the list and buttons at the bottom. I'm trying to get across that the "virtual" screen is too big to fit on one screen even without the ListView there.
我的完整布局对于“物理”屏幕来说太大了,需要滚动才能在底部显示列表的其余部分和按钮。我试图解决“虚拟”屏幕太大而无法放在一个屏幕上的问题,即使那里没有 ListView。
回答by netzpurist
Well, thanks to Rudy, his suggestions was very helpful. Here is how it can be implemented.
好吧,感谢 Rudy,他的建议非常有帮助。这是它的实现方式。
1) Create a new class that extends ListView:
1) 创建一个扩展 ListView 的新类:
package com.example.android.views;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.ListView;
public class ExpandedListView extends ListView {
private android.view.ViewGroup.LayoutParams params;
private int old_count = 0;
public ExpandedListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
if (getCount() != old_count) {
old_count = getCount();
params = getLayoutParams();
params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);
setLayoutParams(params);
}
super.onDraw(canvas);
}
}
2) ... and finally add the new view to your xml layout file:
2) ... 最后将新视图添加到您的 xml 布局文件中:
<com.example.android.views.ExpandedListView
android:id="@+id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollbars="none"
android:padding="0px"
/>
回答by Romain Piel
The correct way to calculate the height is precisely:
计算高度的正确方法是:
int height = 0;
for (int i = 0; i < listView.getChildCount(); i++) {
height += listView.getChildAt(i).getMeasuredHeight();
height += listView.getDividerHeight();
}
回答by alcsan
Attention! Correct way to calculate height is not
注意力!计算高度的正确方法不是
params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);
We have to add height of each (minus one) divider heights.
我们必须添加每个(减一)分隔线高度的高度。
if(oldCount > 0 && getCount() > 0)
params.height = getCount()
* (getChildAt(0).getHeight() + getDividerHeight())
- getDividerHeight();
else
params.height = 0;
回答by dfritsi
@Override
public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
if (this.isExpanded) {
final int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
final ViewGroup.LayoutParams params = this.getLayoutParams();
params.height = this.getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
回答by jqpubliq
If you want a ListView which won't scroll couldn't you just use a LinearLayout?
如果你想要一个不会滚动的 ListView,你不能只使用 LinearLayout 吗?
回答by Cheryl Simon
You should not place your ListView in a ScrollView. The ListView is already scrollable.
您不应将 ListView 放在 ScrollView 中。ListView 已经是可滚动的。
The ListView should expand fully by default, if it is the only thing in the layout.
如果 ListView 是布局中的唯一内容,则默认情况下它应该完全展开。
If it is not the only thing in the layout, and you want the ListView to expand to take up all available space, set the layout_weight on the ListView to 1, where all other layout_weight=0.
如果它不是布局中唯一的东西,并且您希望 ListView 展开以占用所有可用空间,请将 ListView 上的 layout_weight 设置为 1,其中所有其他 layout_weight=0。
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent" orientation="vertical">
<TextView id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ListView id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
Edit: The ListView is really designed to be scrollable...the screen layout you have in your screenshot doesn't really seem like the "android way".
编辑:ListView 真的被设计为可滚动......你在你的屏幕截图中的屏幕布局看起来并不像“android 方式”。
However, if your really want to circumvent that, you could try inflating one of the rows, get its minHeight, and multiply that by the number of items in the ListView adapter.
但是,如果您真的想规避这一点,您可以尝试膨胀其中一行,获取其 minHeight,然后将其乘以 ListView 适配器中的项目数。
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.label_value_row, null, false);
int height = adapter.getCount() * view.getMinHeight();
回答by ASLAN
I took the function from djunod's answer (the function in static class)
我从 djunod 的答案中获取了函数(静态类中的函数)
and change ondraw method as follow. it works after delete operations successfully.
并更改 ondraw 方法如下。它在删除操作成功后工作。
here is my final class
这是我的最后一节课
class ExpandedListView extends ListView {
类 ExpandedListView 扩展了 ListView {
private android.view.ViewGroup.LayoutParams params;
private int old_count = 0;
public ExpandedListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
if (getCount() != old_count) {
params = getLayoutParams();
old_count = getCount();
int totalHeight = 0;
for (int i = 0; i < getCount(); i++) {
this.measure(0, 0);
totalHeight += getMeasuredHeight();
}
params = getLayoutParams();
params.height = totalHeight + (getDividerHeight() * (getCount() - 1));
setLayoutParams(params);
}
super.onDraw(canvas);
}
}
}
now my listview expands after row insert without scrolling. and after row delete this code calculates the correct size for listview. i don't know how it is working. but it is working. BR
现在我的列表视图在行插入后展开而不滚动。行删除后,此代码计算列表视图的正确大小。我不知道它是如何工作的。但它正在工作。BR
回答by vivianChen
use this will be worked:
使用这将起作用:
public class ListViewEx extends ListView {
public ListViewEx(Context context) {
super(context);
}
/**
* @param context
* @param attrs
*/
public ListViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 设置不滚动
*/
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return ev.getAction()==MotionEvent.ACTION_MOVE||super.dispatchTouchEvent(ev);
}
}
}
回答by Lior
I've been researching on how to do this, and although the question has already been answered, I'd like to provide a solution that I think is better:
我一直在研究如何做到这一点,虽然已经回答了这个问题,但我想提供一个我认为更好的解决方案:
Looking at the ListView's source code you can see the following inside the onMeasure(...) code:
查看 ListView 的源代码,您可以在 onMeasure(...) 代码中看到以下内容:
if (heightMode == MeasureSpec.AT_MOST) {
// TODO: after first layout we should maybe start at the first visible position, not 0
heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
}
So simply call the listView's measure and pass MeasureSpec.AT_MOST for the height instead of the usual MeasureSpec.UNSPECIFIED.
因此,只需调用 listView 的度量并通过 MeasureSpec.AT_MOST 代替通常的 MeasureSpec.UNSPECIFIED 来获取高度。
I do the following to measure a listview and place it inside a popup-window:
我执行以下操作来测量列表视图并将其放置在弹出窗口中:
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels, MeasureSpec.AT_MOST);
mCatalogView.measure(widthMeasureSpec, heightMeasureSpec);
mPopup.setWidth(mCatalogView.getMeasuredWidth());
mPopup.setHeight(mCatalogView.getMeasuredHeight());
回答by Shereef Marzouk
I know it's late and there is already and answer but if you really want to do this there is an easy way:
我知道已经晚了,并且已经有了答案,但是如果您真的想这样做,有一个简单的方法:
Create the list view Item with a defined height
创建具有定义高度的列表视图项
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/lvItemSurpriseMeImgRestaurant"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginLeft="5dp"
android:contentDescription="@string/restaurantImageDescriptionColon" />
</LinearLayout>
Now we know that the Item is 100dp
high, and if we know the number of items then it is very simple
现在我们知道Item是100dp
high了,如果我们知道item的数量那就很简单了
set the ListView
height literally to the value of NoOfItems
*Height
+ 10dp
extra
ListView
从字面上将高度设置为NoOfItems
* Height
+ 10dp
extra的值
It will never change since all unites are in dp
.
它永远不会改变,因为所有单位都在dp
.
If you have more than 1 item type then calculate it with basic math and set it
如果您有 1 个以上的项目类型,则使用基本数学计算并设置它
<ListView
android:id="@+id/menuListView"
android:layout_width="match_parent"
android:layout_height="210dp"
android:layout_weight="1.0"
tools:ignore="NestedScrolling"
tools:listitem="@layout/menu_item" >
</ListView>