更改元素可见性时更新布局高度

时间:2013-06-27 12:47:46

标签: android android-listview

在我的布局中,我在一个垂直的LinearLayout中依次放置了两个ListView:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:orientation="vertical"
              android:layout_height="fill_parent">
    <ListView android:id="@+id/events_list"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"/>
    <ListView android:id="@+id/list"
              android:layout_width="fill_parent"
              android:layout_height="wrap_content"/>
</LinearLayout>

我想为第一个ListView onItemClick事件中的每个元素实现,该事件将展开每一行以显示其他信息。

为了实现这一点,我决定在初始适配器getView函数中添加所有元素,但其中一些具有“View.GONE”可见性,然后单击我将其可见性更改为可见。

问题是list元素的初始高度不会扩展,只会添加滚动。

我知道ExpandableListView,但我从未使用它,我不知道它是否适合这个非常简单的案例。


我添加到第一个ListView的元素布局的摘录(可能很有用):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:orientation="horizontal"
              android:layout_height="wrap_content">
...
</LinealLayout>

3 个答案:

答案 0 :(得分:1)

根据您所描述的内容,我认为您需要使用可扩展的列表视图。由于列表视图的工作方式,更新列表中的个别项目很痛苦。 ListView最初只会创建尽可能多的视图来填充屏幕,然后在用户滚动列表时回收这些视图。当然你可以改变价值 - 例如更新文本字段和图片 - 但每次都不会重新填充自己的视图,只更改子元素的内容。这可能就是高度没有变化的原因。适配器显示新的子视图,但在原始膨胀的列表项的高度内这样做。

我可以想到你让这个工作是使用View.INVISIBLE而不是View.GONE。通过这种方式,您可以展示显示所有元素所需的高度视图,并在单击时显示/隐藏。问题是,这不会达到您正在寻找的扩展/合同状态。此外,它将拥有大量丑陋的白色空间,隐藏着物品。

话虽如此,我不知道将所有这些视图元素设置为消失是一个好主意。 ExpandableListView的设计使您可以拥有常规视图并在点击时展开不同的视图。这比为每个视图解析可能的XML元素然后尝试显示/隐藏onClick上的不同字段要高效得多。考虑使用这种方法。它并不比常规列表视图困难得多,并且更适合您尝试做的事情。

答案 1 :(得分:0)

我最终使用非动画技术,例如来自Android示例应用的 Collapsed List 示例。

基本上,他们更改适配器中的布尔变量,并通过发送notifyDatasetChanged()重新绘制整个列表。

答案 2 :(得分:0)

public class NestedListView extends ListView implements OnTouchListener, OnScrollListener {

private int listViewTouchAction;
private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;

public NestedListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    listViewTouchAction = -1;
    setOnScrollListener(this);
    setOnTouchListener(this);
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
    if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
        if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
            scrollBy(0, -1);
        }
    }
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int newHeight = 0;
    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    if (heightMode != MeasureSpec.EXACTLY) {
        ListAdapter listAdapter = getAdapter();
        if (listAdapter != null && !listAdapter.isEmpty()) {
            int listPosition = 0;
            for (listPosition = 0; listPosition < listAdapter.getCount()
                    && listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
                View listItem = listAdapter.getView(listPosition, null, this);
                //now it will not throw a NPE if listItem is a ViewGroup instance
                if (listItem instanceof ViewGroup) {
                    listItem.setLayoutParams(new LayoutParams(
                            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                }
                listItem.measure(widthMeasureSpec, heightMeasureSpec);
                newHeight += listItem.getMeasuredHeight();
            }
            newHeight += getDividerHeight() * listPosition;
        }
        if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
            if (newHeight > heightSize) {
                newHeight = heightSize;
            }
        }
    } else {
        newHeight = getMeasuredHeight();
    }
    setMeasuredDimension(getMeasuredWidth(), newHeight);
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
        if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
            scrollBy(0, 1);
        }
    }
    return false;
}