我怎样才能把一个ListView到一个滚动视图没有崩溃?
我已经search了解决这个问题的方法,唯一的答案我可以find似乎是“ 不要把一个ListView到ScrollView ”。 为什么我还没有看到任何真正的解释。 我似乎发现的唯一原因是Google认为你不应该这样做。 那么我呢,所以我做了。
所以问题是,如何将一个ListView放入一个ScrollView而不会折叠到最小高度?
使用ListView
使其不滚动是非常昂贵的,违背了ListView
的整个目的。 你不应该这样做。 只需使用LinearLayout
。
这是我的解决scheme。 我对Android平台相当陌生,我敢肯定,这有点骇人听闻,特别是在直接调用.measure和直接设置LayoutParams.height
属性的部分,但它的工作原理。
所有你需要做的就是调用Utility.setListViewHeightBasedOnChildren(yourListView)
,它将被resize以精确地适应其项目的高度。
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); } }
这一定会工作…………
您必须使用此Custom ScrollView
<com.tmd.utils.VerticalScrollview > </com.tmd.utils.VerticalScrollview >
replace布局XML文件中的<ScrollView ></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; } }
把ListView
放在一个ScrollView
里面,我们可以使用ListView
作为一个ScrollView
。 必须在ListView
中的东西可以放在ListView
。 在ListView
顶部和底部的其他布局可以通过添加布局到ListView
页眉和页脚来放置。 所以整个ListView
会给你一个滚动的体验。
在很多情况下,在ListView的ScrollView中有很大的意义。
这里的代码基于DougW的build议…在一个片段中工作,占用更less的内存。
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(); }
在每个embedded列表视图上调用setListViewHeightBasedOnChildren(listview)。
ListView实际上已经能够测量自身的高度,足以显示所有项目,但是当您只是指定wrap_content(MeasureSpec.UNSPECIFIED)时,它不会这样做。 当用MeasureSpec.AT_MOST给定高度时,它会这样做。 有了这些知识,你可以创build一个非常简单的子类来解决这个问题,比上面提到的任何解决scheme都要好得多。 你应该仍然使用这个子类的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操作为具有非常大的尺寸(Integer.MAX_VALUE >> 4)的AT_MOST导致ListView测量其所有儿童达到给定的(非常大的)高度,并相应地设置其高度。
由于以下原因,这比其他解决scheme更好:
- 它正确地测量一切(填充,分隔符)
- 它在度量阶段测量ListView
- 由于#2,它正确地处理宽度或数量的变化,没有任何额外的代码
不利的一面是,你可能会认为这样做是依靠SDK中可能会改变的未公开行为。 另一方面,你可能会认为这是wrap_content应该如何与ListView一起工作,并且当前的wrap_content行为已经被破坏了。
如果您担心将来行为可能会发生变化,您应该简单地将onMeasure函数和相关函数从ListView.java中复制到您自己的子类中,然后通过onMeasure将AT_MOSTpath运行为Without。
顺便说一句,我相信当你使用less量的列表项时,这是一个非常有效的方法。 与LinearLayout相比可能效率不高,但是当项目数量很less时,使用LinearLayout是不必要的优化,因此不必要的复杂性。
有一个内置的设置。 在ScrollView上:
android:fillViewport="true"
在Java中,
mScrollView.setFillViewport(true);
罗曼·盖伊在此深入解释: http : //wwwcurious-creature.org/2010/08/15/scrollviews-handy-trick/
我们不能使用两个滚动simulteniuosly。我们将获得总长度的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); }
这是DougW,Good Guy Greg和Paul的答案的组合。 我发现这是所有需要尝试使用此自定义列表视图适配器和非标准列表项目,否则该列表视图坠毁的应用程序(也与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); }
你不应该把ListView放在ScrollView中,因为ListView已经是 ScrollView了。 所以这就像在ScrollView中放置一个ScrollView。
你想完成什么?
嘿,我有一个类似的问题。 我想显示一个列表视图,没有滚动,我发现操作参数工作,但是效率低下,并会在不同的设备上performance不同。因此,这是我的一个日程表代码,这实际上是非常有效的。
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(); } });
在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); } }
这是我发现的最好的方法!
我把@ DougW的Utility
转换成C#(在Xamarin中使用)。 下面的工作适用于列表中的固定高度的项目,如果只有一些项目比标准项目大一些,那么这些项目大部分都是好的,或者至less是一个好的开始。
// 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,当我不得不与其他人的代码一起工作时,这让我摆脱了困境。 🙂
您创build自定义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文件中
创build一个你的customListview的对象,而不是像ListView:NonScrollListView non_scroll_list =(NonScrollListView)findViewById(R.id.lv_nonscroll_list);
之前是不可能的。 但随着新的Appcompat库和devise库的发布,这可以实现。
你只需要使用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>
感谢Vinay在这里的代码是我的代码,当你不能在一个滚动视图内有一个列表视图,但你需要类似的东西
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中,所以它都变成滚动:)
这里是@djunod的答案的小修改,我需要使它完美的工作:
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(); }
试试这个,这对我有用,我忘了我在哪里find它,在堆栈溢出的地方,我不是在这里解释它为什么不起作用,但这是答案:)。
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);
编辑!,我终于find了我的代码。 这里 ! : ScrollView里面的ListView不在Android上滚动
虽然build议的setListViewHeightBasedOnChildren()方法在绝大多数情况下都能正常工作,但在某些情况下,特别是有很多项目,我注意到最后一个元素没有显示出来。 所以我决定模仿一个ListView行为的简单版本,以便重用任何Adapter代码,这里是ListView的替代scheme:
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); } } } }
我使用的解决scheme是,将ListView中的所有ScrollView的内容(应该在ListView之上和之下)添加为headerView和footerView。
所以它的工作原理,也convertview是如何应该的。
所有这些答案都是错误的! 如果你试图在一个滚动视图中放置一个listview,你应该重新考虑你的devise。 你正试图把ScrollView放在ScrollView中。 干扰列表会伤害列表性能。 它的devise就是这样的Android。
If you really want the list to be in the same scroll as the other elements, all you have to do is add the other items into the top of the list using a simple switch statement in your adapter:
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; } }
The list adapter can handle everything since it only renders what is visible.
This whole problem would just go away if LinearLayout had a setAdapter method, because then when you told someone to use it instead the alternative would be trivial.
If you actually want a scrolling ListView inside another scrolling view this won't help, but otherwise this will at least give you an idea.
You need to create a custom adapter to combine all the content you want to scroll over and set the ListView's adapter to that.
I don't have sample code handy, but if you want something like.
<ListView/> (other content) <ListView/>
Then you need to create an adapter that represents all of that content. The ListView/Adapters are smart enough to handle different types as well, but you need to write the adapter yourself.
The android UI API just isn't as mature as pretty much everything else out there, so it doesn't have the same niceties as other platforms. Also, when doing something on android you need to be in an android (unix) mindset where you expect that to do anything you're probably going to have to assemble functionality of smaller parts and write a bunch of your own code to get it to work.
When we place ListView
inside ScrollView
two problems arise. One is ScrollView
measures its children in UNSPECIFIED mode, so ListView
sets its own height to accommodate only one item(I don't know why), another is ScrollView
intercepts the touch event so ListView
does not scrolls.
But we can place ListView
inside ScrollView
with some workaround. This post , by me, explains the workaround. By this workaround we can also retain ListView
's recycling feature as well.
This is the only thing that worked for me:
on Lollipop onwards you can use
yourtListView.setNestedScrollingEnabled(true);
This enable or disable nested scrolling for this view if you need backwards compatibility with older version of the OS you'll have to use the RecyclerView.
This library is the easiest and quickest solution to the problem.
Here is my version of the code that calculates total height of the list view. 这个为我工作:
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(); }
Instead of putting the listview inside Scrollview, put the rest of the content between listview and the opening of the Scrollview as a separate view and set that view as the header of the listview. So you will finally end up only list view taking charge of Scroll.