我到处寻找这个问题的解决方案,我能找到的唯一答案似乎是“不要把一个ListView放入一个ScrollView”。不过,我还没有看到任何真正的解释。我能找到的唯一原因似乎是谷歌认为你不应该这么做。我知道,所以我做了。

问题是,如何将ListView放到ScrollView中而不缩到最小高度?


当前回答

我把@DougW的实用程序转换成c#(在Xamarin中使用)。下面的代码对于列表中固定高度的项目很有效,如果只有一些项目比标准项目稍大一点,那么大多数项目都将很好,或者至少是一个良好的开端。

// You will need to put this Utility class into a code file including various
// libraries, I found that I needed at least System, Linq, Android.Views and 
// Android.Widget.
using System;
using System.Linq;
using Android.Views;
using Android.Widget;

namespace UtilityNamespace  // whatever you like, obviously!
{
    public class Utility
    {
        public static void setListViewHeightBasedOnChildren (ListView listView)
        {
            if (listView.Adapter == null) {
                // pre-condition
                return;
            }

            int totalHeight = listView.PaddingTop + listView.PaddingBottom;
            for (int i = 0; i < listView.Count; i++) {
                View listItem = listView.Adapter.GetView (i, null, listView);
                if (listItem.GetType () == typeof(ViewGroup)) {
                    listItem.LayoutParameters = new LinearLayout.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
                }
                listItem.Measure (0, 0);
                totalHeight += listItem.MeasuredHeight;
            }

            listView.LayoutParameters.Height = totalHeight + (listView.DividerHeight * (listView.Count - 1));
        }
    }
}

谢谢@DougW,当我不得不使用其他人的代码时,这让我摆脱了困境。: -)

其他回答

这肯定会工作............ 你必须替换你的<ScrollView ></ScrollView>在布局XML文件与这个自定义ScrollView像<com.tmd.utils。VerticalScrollview > </com.tmd.utils。VerticalScrollview >

package com.tmd.utils;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;

public class VerticalScrollview extends ScrollView{

    public VerticalScrollview(Context context) {
        super(context);
    }

     public VerticalScrollview(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" );
                    super.onTouchEvent(ev);
                    break;

            case MotionEvent.ACTION_MOVE:
                    return false; // redirect MotionEvents to ourself

            case MotionEvent.ACTION_CANCEL:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" );
                    super.onTouchEvent(ev);
                    break;

            case MotionEvent.ACTION_UP:
                    Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" );
                    return false;

            default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break;
        }

        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        super.onTouchEvent(ev);
        Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
         return true;
    }
}

嘿,我也有类似的问题。我想显示一个列表视图,不滚动,我发现操纵参数工作,但效率低,会在不同的设备上表现不同。因此,这是我的一段调度代码,它实际上非常有效地完成了这个任务。

db = new dbhelper(this);

 cursor = db.dbCursor();
int count = cursor.getCount();
if (count > 0)
{    
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.layoutId);
startManagingCursor(YOUR_CURSOR);

YOUR_ADAPTER(**or SimpleCursorAdapter **) adapter = new YOUR_ADAPTER(this,
    R.layout.itemLayout, cursor, arrayOrWhatever, R.id.textViewId,
    this.getApplication());

int i;
for (i = 0; i < count; i++){
  View listItem = adapter.getView(i,null,null);
  linearLayout.addView(listItem);
   }
}

注意:如果你使用这个,notifyDataSetChanged();将不会像预期的那样工作,因为视图将不会被重绘。 如果你需要变通,就这么做

adapter.registerDataSetObserver(new DataSetObserver() {

            @Override
            public void onChanged() {
                super.onChanged();
                removeAndRedrawViews();

            }

        });

你创建了一个自定义的ListView,它是不可滚动的

public class NonScrollListView extends ListView {

    public NonScrollListView(Context context) {
        super(context);
    }
    public NonScrollListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                    Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();    
    }
}

在布局资源文件中

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <!-- com.Example Changed with your Package name -->

    <com.Example.NonScrollListView
        android:id="@+id/lv_nonscroll_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </com.Example.NonScrollListView>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/lv_nonscroll_list" >

        <!-- Your another layout in scroll view -->

    </RelativeLayout>
</RelativeLayout>

在Java文件中

创建一个customListview对象而不是ListView,如下所示: NonScrollListView non_scroll_list = (NonScrollListView) findViewById(R.id.lv_nonscroll_list);

下面是我的计算列表视图总高度的代码版本。这个对我很有用:

   public static void setListViewHeightBasedOnChildren(ListView listView) {
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null || listAdapter.getCount() < 2) {
        // pre-condition
        return;
    }

    int totalHeight = 0;
    int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(BCTDApp.getDisplaySize().width, View.MeasureSpec.AT_MOST);
    int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

    for (int i = 0; i < listAdapter.getCount(); i++) {
        View listItem = listAdapter.getView(i, null, listView);
        if (listItem instanceof ViewGroup) listItem.setLayoutParams(lp);
        listItem.measure(widthMeasureSpec, heightMeasureSpec);
        totalHeight += listItem.getMeasuredHeight();
    }

    totalHeight += listView.getPaddingTop() + listView.getPaddingBottom();
    totalHeight += (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight;
    listView.setLayoutParams(params);
    listView.requestLayout();
}

ListView实际上已经能够测量自身的高度以显示所有项,但是当您简单地指定wrap_content (measurespect . unspecified)时,它不能这样做。当给出一个带有measurespect . at_most的高度时,它将这样做。有了这些知识,你可以创建一个非常简单的子类来解决这个问题,它比上面发布的任何解决方案都要好得多。您仍然应该对这个子类使用wrap_content。

public class ListViewForEmbeddingInScrollView extends ListView {
    public ListViewForEmbeddingInScrollView(Context context) {
        super(context);
    }

    public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
    }
}

操纵heightMeasureSpec为AT_MOST,具有非常大的大小(整数。MAX_VALUE >> 4)导致ListView测量它的所有子节点直到给定的(非常大的)高度,并相应地设置它的高度。

这比其他解决方案更好,原因如下:

它可以正确测量所有内容(填充,分隔线) 它在测量过程中测量ListView 由于#2,它正确地处理宽度或项目数量的变化,而不需要任何额外的代码

缺点是,您可能会认为这样做依赖于SDK中未记录的行为,而这些行为可能会更改。另一方面,你可能认为这就是wrap_content与ListView一起工作的方式,而当前的wrap_content行为只是被破坏了。

如果你担心行为可能会在未来发生变化,你应该简单地复制onMeasure函数和相关函数从ListView.java和到你自己的子类,然后使AT_MOST路径通过onMeasure运行为未指定的以及。

顺便说一下,我相信当您处理少量列表项时,这是一种非常有效的方法。与线性布局相比,它可能效率较低,但当项目数量较少时,使用线性布局是不必要的优化,因此也会造成不必要的复杂性。