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

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


当前回答

不是把listview放在Scrollview里面,而是把其余的内容放在listview和Scrollview的开头之间,作为一个单独的视图,并将该视图设置为listview的头部。所以你最终将只有列表视图负责滚动。

其他回答

以前这是不可能的。但是随着新的Appcompat库和Design库的发布,这可以实现。

你只需要使用NestedScrollView https://developer.android.com/reference/android/support/v4/widget/NestedScrollView.html

我不知道它将与Listview工作与否,但与RecyclerView工作。

代码片段:

<android.support.v4.widget.NestedScrollView 
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

</android.support.v4.widget.NestedScrollView>

在ScrollView中使用ListView有两个问题。

ListView必须完全展开到它的子节点高度。这个ListView解决这个问题:

public class ListViewExpanded extends ListView
{
    public ListViewExpanded(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        setDividerHeight(0);
    }

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

分隔高度必须为0,在行中使用填充代替。

2- ListView消耗触摸事件,所以ScrollView不能像往常一样滚动。这个ScrollView解决了这个问题:

public class ScrollViewInterceptor extends ScrollView
{
    float startY;

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e)
    {
        onTouchEvent(e);
        if (e.getAction() == MotionEvent.ACTION_DOWN) startY = e.getY();
        return (e.getAction() == MotionEvent.ACTION_MOVE) && (Math.abs(startY - e.getY()) > 50);
    }
}

这是我发现的最好的方法!

如果LinearLayout有一个setAdapter方法,整个问题就会消失,因为当你告诉别人使用它时,替代方案将是微不足道的。

如果你想要一个滚动的ListView在另一个滚动视图中,这不会有帮助,但至少会给你一个想法。

您需要创建一个自定义适配器来组合要滚动的所有内容,并将ListView的适配器设置为该内容。

我手头没有样本代码,但如果你想要。

<ListView/>

(other content)

<ListView/>

然后需要创建一个表示所有这些内容的适配器。ListView/Adapters也足够智能,可以处理不同的类型,但是您需要自己编写适配器。

android的UI API并不像其他平台那么成熟,所以它不像其他平台那么精致。此外,当你在android上做一些事情时,你需要以android (unix)的心态来做任何事情,你可能不得不将更小的部分的功能组装起来,并编写一堆自己的代码来让它工作。

虽然建议的setListViewHeightBasedOnChildren()方法在大多数情况下都可以工作,但在某些情况下,特别是对于许多项,我注意到最后一个元素不显示。所以我决定模仿一个简单版本的ListView行为,以便重用任何适配器代码,这里是ListView的替代方案:

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListAdapter;

public class StretchedListView extends LinearLayout {

private final DataSetObserver dataSetObserver;
private ListAdapter adapter;
private OnItemClickListener onItemClickListener;

public StretchedListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setOrientation(LinearLayout.VERTICAL);
    this.dataSetObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            syncDataFromAdapter();
            super.onChanged();
        }

        @Override
        public void onInvalidated() {
            syncDataFromAdapter();
            super.onInvalidated();
        }
    };
}

public void setAdapter(ListAdapter adapter) {
    ensureDataSetObserverIsUnregistered();

    this.adapter = adapter;
    if (this.adapter != null) {
        this.adapter.registerDataSetObserver(dataSetObserver);
    }
    syncDataFromAdapter();
}

protected void ensureDataSetObserverIsUnregistered() {
    if (this.adapter != null) {
        this.adapter.unregisterDataSetObserver(dataSetObserver);
    }
}

public Object getItemAtPosition(int position) {
    return adapter != null ? adapter.getItem(position) : null;
}

public void setSelection(int i) {
    getChildAt(i).setSelected(true);
}

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
    this.onItemClickListener = onItemClickListener;
}

public ListAdapter getAdapter() {
    return adapter;
}

public int getCount() {
    return adapter != null ? adapter.getCount() : 0;
}

private void syncDataFromAdapter() {
    removeAllViews();
    if (adapter != null) {
        int count = adapter.getCount();
        for (int i = 0; i < count; i++) {
            View view = adapter.getView(i, null, this);
            boolean enabled = adapter.isEnabled(i);
            if (enabled) {
                final int position = i;
                final long id = adapter.getItemId(position);
                view.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        if (onItemClickListener != null) {
                            onItemClickListener.onItemClick(null, v, position, id);
                        }
                    }
                });
            }
            addView(view);

        }
    }
}
}

我们不能同时使用两个滚动。我们将获得ListView的总长度,并用总高度展开ListView。然后我们可以直接或使用线性布局在ScrollView中添加ListView,因为ScrollView直接有一个子。 在你的代码中复制setListViewHeightBasedOnChildren(lv)方法并展开listview,然后你可以在scrollview中使用listview。 \layout XML文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
 <ScrollView

        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
         android:background="#1D1D1D"
        android:orientation="vertical"
        android:scrollbars="none" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#1D1D1D"
            android:orientation="vertical" >

            <TextView
                android:layout_width="fill_parent"
                android:layout_height="40dip"
                android:background="#333"
                android:gravity="center_vertical"
                android:paddingLeft="8dip"
                android:text="First ListView"
                android:textColor="#C7C7C7"
                android:textSize="20sp" />

            <ListView
                android:id="@+id/first_listview"
                android:layout_width="260dp"
                android:layout_height="wrap_content"
                android:divider="#00000000"
               android:listSelector="#ff0000"
                android:scrollbars="none" />

               <TextView
                android:layout_width="fill_parent"
                android:layout_height="40dip"
                android:background="#333"
                android:gravity="center_vertical"
                android:paddingLeft="8dip"
                android:text="Second ListView"
                android:textColor="#C7C7C7"
                android:textSize="20sp" />

            <ListView
                android:id="@+id/secondList"
                android:layout_width="260dp"
                android:layout_height="wrap_content"
                android:divider="#00000000"
                android:listSelector="#ffcc00"
                android:scrollbars="none" />
  </LinearLayout>
  </ScrollView>

   </LinearLayout>

Activity类中的onCreate方法:

 import java.util.ArrayList;
  import android.app.Activity;
 import android.os.Bundle;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
  import android.widget.ListView;

   public class MainActivity extends Activity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.listview_inside_scrollview);
    ListView list_first=(ListView) findViewById(R.id.first_listview);
    ListView list_second=(ListView) findViewById(R.id.secondList);
    ArrayList<String> list=new ArrayList<String>();
    for(int x=0;x<30;x++)
    {
        list.add("Item "+x);
    }

       ArrayAdapter<String> adapter=new ArrayAdapter<String>(getApplicationContext(), 
          android.R.layout.simple_list_item_1,list);               
      list_first.setAdapter(adapter);

     setListViewHeightBasedOnChildren(list_first);

      list_second.setAdapter(adapter);

    setListViewHeightBasedOnChildren(list_second);
   }



   public static 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);
        listItem.measure(0, 0);
        totalHeight += listItem.getMeasuredHeight();
    }

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