首页 文章

如何在没有折叠的情况下将ListView放入ScrollView?

提问于
浏览
337

我一直在寻找这个问题的解决方案,我能找到的唯一答案似乎是“don't put a ListView into a ScrollView” . 我还没有看到任何真正的解释为什么 . 我似乎找到的唯一原因是Google认为你不应该这样做 . 好吧,我做了,所以我做到了 .

所以问题是,如何将ListView放入ScrollView而不将其折叠到最小高度?

27 回答

  • 8

    This库是解决该问题的最简单,最快捷的解决方案 .

  • 1

    使用 ListView 使其不滚动是非常昂贵的,并违背 ListView 的整个目的 . 你应该 NOT 这样做 . 只需使用 LinearLayout .

  • 1

    这里's my solution. I'对于Android平台来说相当新,我确信这有点hackish,特别是关于直接调用.measure并直接设置 LayoutParams.height 属性的部分,但是它有效 .

    您所要做的就是调用 Utility.setListViewHeightBasedOnChildren(yourListView) ,它将调整大小以准确容纳其项目的高度 .

    public class Utility {
        public static void setListViewHeightBasedOnChildren(ListView listView) {
            ListAdapter listAdapter = listView.getAdapter();
            if (listAdapter == null) {
                // pre-condition
                return;
            }
    
            int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
    
            for (int i = 0; i < listAdapter.getCount(); i++) {
                View listItem = listAdapter.getView(i, null, listView);
                if (listItem instanceof ViewGroup) {
                    listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                 }
    
                 listItem.measure(0, 0);
                 totalHeight += listItem.getMeasuredHeight();
            }
    
            ViewGroup.LayoutParams params = listView.getLayoutParams();
            params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
            listView.setLayoutParams(params);
        }
    }
    
  • 1

    This will definitely work............
    你必须用 Custom ScrollView 替换 <ScrollView ></ScrollView> 布局XML文件,如 <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;
        }
    }
    
  • 24

    如果将 ListView 放在 ScrollView 中,我们可以使用 ListView 作为 ScrollView . 必须在 ListView 中的东西可以放在 ListView 内 . 通过在 ListView 的页眉和页脚中添加布局,可以放置 ListView 顶部和底部的其他布局 . 因此整个 ListView 将为您提供滚动体验 .

  • 86

    在很多情况下,在ScrollView中使用ListView非常有意义 .

    这里的代码基于DougW的建议......在片段中工作,占用更少的内存 .

    public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            return;
        }
        int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
        int totalHeight = 0;
        View view = null;
        for (int i = 0; i < listAdapter.getCount(); i++) {
            view = listAdapter.getView(i, view, listView);
            if (i == 0) {
                view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, LayoutParams.WRAP_CONTENT));
            }
            view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
            totalHeight += view.getMeasuredHeight();
        }
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
        listView.requestLayout();
    }
    

    在每个嵌入式列表视图上调用setListViewHeightBasedOnChildren(listview) .

  • 0

    ListView实际上已经能够测量自身足够高以显示所有项目,但是当您只是指定wrap_content(MeasureSpec.UNSPECIFIED)时它不会这样做 . 当使用MeasureSpec.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(Integer.MAX_VALUE >> 4)会导致ListView测量其所有子节点到达给定(非常大)的高度并相应地设置其高度 .

    由于以下几个原因,这比其他解决方案效果更好:

    • 它正确测量一切(填充,分隔)

    • 它在度量过程中测量ListView

    • 由于#2,它无需任何额外代码即可正确处理项目宽度或数量的变化

    在缺点方面,您可能会认为这样做依赖于SDK中可能发生变化的无证行为 . 另一方面,您可能会认为这就是wrap_content应该如何与ListView一起使用,并且当前的wrap_content行为刚刚被破坏 .

    如果你担心将来会改变这种行为,你应该简单地将onMeasure函数和相关函数从ListView.java复制到你自己的子类中,然后通过onMeasure运行AT_MOST路径也可以运行 .

    顺便说一句,我相信当你处理少量列表项时,这是一种非常有效的方法 . 与LinearLayout相比,它可能效率低,但是当项目数量较少时,使用LinearLayout是不必要的优化,因此不必要的复杂性 .

  • 2

    它有一个内置的设置 . 在ScrollView上:

    android:fillViewport="true"
    

    在Java中

    mScrollView.setFillViewport(true);
    

    Romain Guy在这里深入解释:http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/

  • 1

    我们不能使用两个滚动simulteniuosly . 我们将获得ListView的总长度并使用总高度扩展listview . 然后我们可以直接在ScrollView中添加ListView或使用LinearLayout,因为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);
          }
    
  • 189

    您创建不可滚动的自定义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);

  • 8

    这是DougW,Good Guy Greg和Paul的答案的组合 . 我发现在尝试使用自定义列表视图适配器和非标准列表项时都需要它,否则listview会崩溃应用程序(也会被Nex的答案崩溃):

    public void setListViewHeightBasedOnChildren(ListView listView) {
            ListAdapter listAdapter = listView.getAdapter();
            if (listAdapter == null) {
                return;
            }
    
            int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
            for (int i = 0; i < listAdapter.getCount(); i++) {
                View listItem = listAdapter.getView(i, null, listView);
                if (listItem instanceof ViewGroup)
                    listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                listItem.measure(0, 0);
                totalHeight += listItem.getMeasuredHeight();
            }
    
            ViewGroup.LayoutParams params = listView.getLayoutParams();
            params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
            listView.setLayoutParams(params);
        }
    
  • 2

    我将@ DougW的 Utility 转换为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,当我不得不使用OtherPeople的代码时,这让我摆脱了困境 . :-)

  • -1

    您不应该将ListView放在ScrollView中,因为ListView已经是ScrollView . 这就像将ScrollView放在ScrollView中一样 .

    你想达到什么目的?

  • 254

    嘿我有类似的问题 . 我想显示一个没有滚动的列表视图,我发现操作参数有效但效率低,并且在不同的设备上表现不同......因此,这是我的计划代码的一部分,实际上非常有效地执行此操作 .

    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();
    
                }
    
            });
    
  • 0

    在ScrollView中使用ListView时有两个问题 .

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

    这是我发现的最好方法!

  • 3

    This is the only thing that worked for me:

    在棒棒糖上你可以使用

    yourtListView.setNestedScrollingEnabled(true);
    

    如果您需要向后兼容您必须使用RecyclerView的旧版操作系统,则启用或禁用此视图的嵌套滚动 .

  • 0

    感谢Vinay's code这里是我的代码,当你在滚动视图中没有列表视图但你需要类似的东西

    LayoutInflater li = LayoutInflater.from(this);
    
                    RelativeLayout parent = (RelativeLayout) this.findViewById(R.id.relativeLayoutCliente);
    
                    int recent = 0;
    
                    for(Contatto contatto : contatti)
                    {
                        View inflated_layout = li.inflate(R.layout.header_listview_contatti, layout, false);
    
    
                        inflated_layout.setId(contatto.getId());
                        ((TextView)inflated_layout.findViewById(R.id.textViewDescrizione)).setText(contatto.getDescrizione());
                        ((TextView)inflated_layout.findViewById(R.id.textViewIndirizzo)).setText(contatto.getIndirizzo());
                        ((TextView)inflated_layout.findViewById(R.id.textViewTelefono)).setText(contatto.getTelefono());
                        ((TextView)inflated_layout.findViewById(R.id.textViewMobile)).setText(contatto.getMobile());
                        ((TextView)inflated_layout.findViewById(R.id.textViewFax)).setText(contatto.getFax());
                        ((TextView)inflated_layout.findViewById(R.id.textViewEmail)).setText(contatto.getEmail());
    
    
    
                        RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
    
                        if (recent == 0)
                        {
                            relativeParams.addRule(RelativeLayout.BELOW, R.id.headerListViewContatti);
                        }
                        else
                        {
                            relativeParams.addRule(RelativeLayout.BELOW, recent);
                        }
                        recent = inflated_layout.getId();
    
                        inflated_layout.setLayoutParams(relativeParams);
                        //inflated_layout.setLayoutParams( new RelativeLayout.LayoutParams(source));
    
                        parent.addView(inflated_layout);
                    }
    

    relativeLayout保留在ScrollView中,所以它都变得可滚动了:)

  • 0

    这是对@djunodanswer的小修改,我需要让它完美地运作:

    public static void setListViewHeightBasedOnChildren(ListView listView)
    {
        ListAdapter listAdapter = listView.getAdapter();
        if(listAdapter == null) return;
        if(listAdapter.getCount() <= 1) return;
    
        int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.AT_MOST);
        int totalHeight = 0;
        View view = null;
        for(int i = 0; i < listAdapter.getCount(); i++)
        {
            view = listAdapter.getView(i, view, listView);
            view.measure(desiredWidth, MeasureSpec.UNSPECIFIED);
            totalHeight += view.getMeasuredHeight();
        }
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
        listView.requestLayout();
    }
    
  • 4

    试试这个,这对我有用,我忘了我发现它的地方,堆栈溢出的地方,我不是在这里解释它为什么它不起作用,但这是答案:) .

    final ListView AturIsiPulsaDataIsiPulsa = (ListView) findViewById(R.id.listAturIsiPulsaDataIsiPulsa);
        AturIsiPulsaDataIsiPulsa.setOnTouchListener(new ListView.OnTouchListener() 
        {
            @Override
            public boolean onTouch(View v, MotionEvent event) 
            {
                int action = event.getAction();
                switch (action) 
                {
                    case MotionEvent.ACTION_DOWN:
                    // Disallow ScrollView to intercept touch events.
                    v.getParent().requestDisallowInterceptTouchEvent(true);
                    break;
    
                    case MotionEvent.ACTION_UP:
                    // Allow ScrollView to intercept touch events.
                    v.getParent().requestDisallowInterceptTouchEvent(false);
                    break;
                }
    
                // Handle ListView touch events.
                v.onTouchEvent(event);
                return true;
            }
        });
        AturIsiPulsaDataIsiPulsa.setClickable(true);
        AturIsiPulsaDataIsiPulsa.setAdapter(AturIsiPulsaDataIsiPulsaAdapter);
    

    编辑!,我终于找到了我得到代码的地方 . 这里 ! :ListView inside ScrollView is not scrolling on Android

  • 15

    虽然建议的 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);
    
            }
        }
    }
    }
    
  • 1

    我使用的解决方案是将ListView中的所有ScrollView内容(应该在listView上面和下面)添加为headerView和footerView .

    所以它的工作原理,转换视图也应该如何重新启动 .

  • 1

    所有这些答案都是错误的!如果您尝试将列表视图放在滚动视图中,则应重新考虑您的设计 . 您正在尝试将ScrollView放入ScrollView中 . 干扰列表会损害列表性能 . Android的设计就是这样的 .

    如果您确实希望列表与其他元素位于同一个滚动中,您只需使用适配器中的简单switch语句将其他项添加到列表顶部:

    class MyAdapter extends ArrayAdapter{
    
        public MyAdapter(Context context, int resource, List objects) {
            super(context, resource, objects);
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
             ViewItem viewType = getItem(position);
    
            switch(viewType.type){
                case TEXTVIEW:
                    convertView = layouteInflater.inflate(R.layout.textView1, parent, false);
    
                    break;
                case LISTITEM:
                    convertView = layouteInflater.inflate(R.layout.listItem, parent, false);
    
                    break;            }
    
    
            return convertView;
        }
    
    
    }
    

    列表适配器可以处理所有内容,因为它只呈现可见内容 .

  • 2

    在它不可能之前 . 但随着新的Appcompat库和设计库的发布,这可以实现 .

    你只需要使用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>
    
  • 12

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

    如果你真的想要在另一个滚动视图中滚动ListView,这将无济于事,但除此之外,这至少会给你一个想法 .

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

    我没有方便的示例代码,但如果你想要类似的东西 .

    <ListView/>
    
    (other content)
    
    <ListView/>
    

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

    Android UI API并不像其他所有其他平台那样成熟,因此它没有与其他平台相同的细节 . 此外,当你在Android上做一些事情时,你需要处于一个android(unix)思维模式,在那里你期望做任何你可能需要组装较小部分功能的东西,并编写一堆你自己的代码来实现它工作 .

  • 1

    当我们在 ScrollView 里面放置 ListView 时会出现两个问题 . 一个是 ScrollView 测量其处于非正式模式的子项,因此 ListView 设置自己的高度以仅容纳一个项目(我不知道为什么),另一个是 ScrollView 拦截触摸事件因此 ListView 不滚动 .

    但我们可以在 ScrollView 中放置 ListView 并进行一些解决方法 . This post,由我解释了解决方法 . 通过这种解决方法,我们也可以保留 ListView 的回收功能 .

  • 20

    而不是把列表视图在Scrollview内部,将listview和Scrollview的开头之间的其余内容作为单独的视图放置,并将该视图设置为listview的 Headers . 因此,您最终只会获得负责Scroll的列表视图 .

  • 2

    这是我的代码版本,用于计算列表视图的总高度 . 这个对我有用:

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

相关问题