计算列表视图的大小或如何告诉它完全展开

时间:2010-02-22 17:18:27

标签: android

我目前正在尝试在ScrollView中使用ListView。我知道从我读过的内容中看到了这一点,但是我试图通过显示所有行来完全展开ListView,因此不需要滚动它。然而,我一直在努力告诉ListView完全展开以显示它的所有行,因为它需要一个定义的高度。有没有人知道在绘制之前计算完全展开的ListView的高度的方法?

此问题主要源于您无法将可滚动视图放在另一个可滚动视图中。我很好,因为ListView将无法滚动,只要我可以展开它以显示其所有行。但是,我无法做到这一点,但却无法给它定义一个高度,这似乎是我需要计算的。

请参阅下面的URL以获取草图(我是新用户,所以我不允许发布一个)。它表明我的完整布局对于“物理”屏幕来说太大了,需要滚动以显示列表的其余部分和底部的按钮。我试图弄清楚即使没有ListView,“虚拟”屏幕也太大而无法放在一个屏幕上。

http://img51.imageshack.us/img51/7210/screenmockup.png

12 个答案:

答案 0 :(得分:56)

好吧,多谢Rudy,他的建议很有帮助。以下是它的实施方式。

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)...最后将新视图添加到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"
    />

答案 1 :(得分:14)

计算高度的正确方法正是:

int height = 0;
for (int i = 0; i < listView.getChildCount(); i++) {
    height += listView.getChildAt(i).getMeasuredHeight();
    height += listView.getDividerHeight();
}

答案 2 :(得分:11)

注意! 正确的计算高度的方法不是

params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight() : 0);

我们必须添加每个(减1)分频器高度的高度。

if(oldCount > 0 && getCount() > 0)
    params.height = getCount()
                  * (getChildAt(0).getHeight() + getDividerHeight())
                  - getDividerHeight();
else
    params.height = 0;

答案 3 :(得分:4)

@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);
    }
}

答案 4 :(得分:3)

如果你想要一个不能滚动的ListView你不能只使用一个LinearLayout?

答案 5 :(得分:2)

您不应将ListView放在ScrollView中。 ListView已经可滚动了。

如果布局中唯一的东西,ListView应该默认完全展开。

如果它不是布局中的唯一内容,并且您希望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>

编辑: ListView真的被设计成可滚动的...你的截图中的屏幕布局看起来并不像“android方式”。

但是,如果您真的想要绕过它,可以尝试对其中一行进行充气,获取其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();

答案 6 :(得分:1)

我一直在研究如何做到这一点,虽然问题已经得到解答,但我想提供一个我认为更好的解决方案:

查看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);
}

因此,只需调用listView的度量并传递MeasureSpec.AT_MOST作为高度,而不是通常的MeasureSpec.UNSPECIFIED。

我执行以下操作来测量列表视图并将其放在弹出窗口中:

    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());

答案 7 :(得分:1)

我从djunod的答案中获取了这个函数(静态类中的函数)

calculate listview size

并更改提取方法如下。 它在删除操作成功后有效。

这是我的最后一堂课

class 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);
}

}

现在我的listview在没有滚动的行插入后展开。 删除行后,此代码计算listview的正确大小。 我不知道它是如何工作的。 但它正在发挥作用。 BR

答案 8 :(得分:1)

使用它将起作用:

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);
}

}

答案 9 :(得分:0)

我最终覆盖了ListView的onDraw()并计算了视图中可见行的平均高度,然后根据适配器中的项目数估计列表的实际高度。这种估计会发生几次,直到所有行都可见。

答案 10 :(得分:0)

我知道它已经很晚了已经有了回答但是如果你真的想这样做有一个简单的方法:

创建具有已定义高度的列表视图项

<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>

现在我们知道项目是100dp高,如果我们知道项目数量那么它很简单

ListView高度字面设置为NoOfItems * Height + 10dp额外

的值

它永远不会改变,因为所有单位都在dp

如果您有多个项目类型,请使用基本数学计算并设置

        <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>

答案 11 :(得分:0)

如果您有不同身高的物品,则需要使用此方法:

public void setListViewHeightBasedOnChildren(ListView listView) {

    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter != null) {

        int numberOfItems = listAdapter.getCount();

        // Get total height of all items.
        int totalItemsHeight = 0;
        for (int itemPos = 0; itemPos < numberOfItems; itemPos++) {
            View item = listAdapter.getView(itemPos, null, listView);
            float px = 300 * (listView.getResources().getDisplayMetrics().density);
            item.measure(
                    View.MeasureSpec.makeMeasureSpec((int)px, View.MeasureSpec.AT_MOST),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            int height = item.getMeasuredHeight();
            totalItemsHeight += height;
        }

        // Get total height of all item dividers.
        int totalDividersHeight = listView.getDividerHeight() *
                (numberOfItems - 1);

        // Set list height.
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalItemsHeight + totalDividersHeight;
        listView.setLayoutParams(params);
        listView.requestLayout();
    }
}

任何带有任何项目的ListView都能正常工作