滚动视图中的Android列表视图

我有一个android的布局,其中有一个与许多元素的scrollView 。 在scrollView的底部,我有一个listView ,然后由适配器填充。

我遇到的问题是,Android是从scrollView排除listView作为scrollView已经有一个可滚动function。 我想listView只要内容是和主滚动视图是可滚动的。

我怎样才能做到这一点?

这是我的主要布局:

 <ScrollView android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="2" android:fillViewport="true" android:gravity="top" > <LinearLayout android:id="@+id/foodItemActvity_linearLayout_fragments" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > </LinearLayout> </ScrollView> 

然后以编程方式将我的组件添加到具有id: foodItemActvity_linearLayout_fragments 。 下面是加载到该线性布局的视图之一。 这是给我卷轴的麻烦。

 <?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="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/fragment_dds_review_textView_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Reviews:" android:textAppearance="?android:attr/textAppearanceMedium" /> <ListView android:id="@+id/fragment_dds_review_listView" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout> 

我的适配器然后填写这个列表视图。

当我点击主scrollView时,这是一个android层次结构查看器的图像:

滚动视图中的Android列表视图

正如你所看到的,它不包括评论listView。

我应该可以将页面向下滚动并查看8条评论,而是只显示了那3条,我可以在评论所在的小部分上滚动。 我想要一个全局的页面滚动

ScrollView问题中ListView最短和最简单的解决scheme

您不必在layout.xml文件中做任何特殊处理,也不需要处理父ScrollView上的任何内容。 你只需要处理子ListView您也可以使用此代码在ScrollView中使用任何types的子视图并执行Touch操作。

只需在你的java类中添加这些代码行:

 ListView lv = (ListView) findViewById(R.id.layout_lv); lv.setOnTouchListener(new OnTouchListener() { // Setting on Touch Listener for handling the touch inside ScrollView @Override public boolean onTouch(View v, MotionEvent event) { // Disallow the touch request for parent scroll on touch of child view v.getParent().requestDisallowInterceptTouchEvent(true); return false; } }); 

如果你把ListView放在一个ScrollView中,那么所有的ListView都不会伸展到它的全部高度 。 下面是一个解决这个问题的方法。

 /**** Method for Setting the Height of the ListView dynamically. **** Hack to fix the issue of not showing all the items of the ListView **** when placed inside a ScrollView ****/ public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) return; int desiredWidth = MeasureSpec.makeMeasureSpec(listView.getWidth(), MeasureSpec.UNSPECIFIED); 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:

 ListView list = (ListView) view.findViewById(R.id.ls); setListViewHeightBasedOnChildren(list); 

用于ExpandableListView – 信用Benny

 ExpandableListView: view = listAdapter.getView(0, view, listView); int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.MATCH_PARENT, View.MeasureSpec.EXACTLY); int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.EXACTLY); view.measure(widthMeasureSpec, heightMeasureSpec); 

对于具有variables项目高度的ListView,请使用下面的链接:

ScrollView里面的ListView不在Android上滚动

让图书馆直接在你的代码 – 信用保罗罗托洛实施

https://github.com/PaoloRotolo/ExpandableHeightListView

答案很简单,我很惊讶这里还没有答案。

在列表本身上使用Header View或/和Footer View 。 不要将ScrollViewListView或任何可以滚动的东西混合使用。 它的意思是用于页眉和页脚:)

从本质上讲,把所有的内容放在你的ListView之上,把它放在另一个.xml文件中作为一个布局,然后在代码中膨胀它,并把它作为一个标题视图添加到列表中。

 View header = getLayoutInflater().inflate(R.layout.header, null); View footer = getLayoutInflater().inflate(R.layout.footer, null); listView.addHeaderView(header); listView.addFooterView(footer); 

我知道它已经这么久了,但是我也遇到了这个问题,尝试了这个解决scheme,它正在工作。 所以我想这也可以帮助其他人。

我在scrollView的layout xml中添加了android:fillViewport =“true”。 所以总体上我的ScrollView会是这样的。

 <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/scrollView6" android:fillViewport="true"> 

它对我来说就像魔术一样。 位于我的ScrollView内的ListView再次展开为其大小。

以下是ScrollView和ListView的完整示例代码。

 <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/scrollView6" android:fillViewport="true"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> .... <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/lv_transList" android:layout_gravity="top" android:layout_marginTop="5dp"/> .... </LinearLayout> </ScrollView> 

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

在您的布局资源文件

  <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fadingEdgeLength="0dp" android:fillViewport="true" android:overScrollMode="never" android:scrollbars="none" > <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> </ScrollView> 

在Java文件中创build您的customListview而不是ListView的对象,如: NonScrollListView non_scroll_list =(NonScrollListView)findViewById(R.id.lv_nonscroll_list);

你可以通过在ScrollView中添加android:fillViewport="true"来解决这个问题。

 <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:fillViewport="true" android:scrollbars="vertical"> <ListView android:id="@+id/statusList" android:layout_width="fill_parent" android:layout_height="wrap_content" android:animationCache="false" android:divider="@null" android:scrollingCache="false" android:smoothScrollbar="true" /> </ScrollView> 

在使用该属性之前,我的列表视图中只有一个孩子可见。 在使用之后,列表的所有行或子都可见。

  public static void setListViewHeightBasedOnChildren(ListView listView) { // 获取ListView对应的Adapter ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = 0; for (int i = 0, len = listAdapter.getCount(); i < len; i++) { // listAdapter.getCount()返回数据项的数目View listItem = listAdapter.getView(i, null, listView); listItem.measure(0, 0); // 计算子项View 的宽高totalHeight += listItem.getMeasuredHeight(); // 统计所有子项的总高度} ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); // listView.getDividerHeight()获取子项间分隔符占用的高度// params.height最后得到整个ListView完整显示需要的高度listView.setLayoutParams(params); } 

您可以在滚动视图中使用此代码的ListView

我会把它留在这里,以防有人会面对同样的问题。 我不得不在ScrollView中放置一个ListView。 带有标题的ListView不是一个选项,由于多种原因。 也没有select使用LinearLayout而不是ListView。 所以我遵循接受的解决scheme,但它不工作,因为列表中的项目具有复杂的布局与多行,每个列表视图项目是可变高度。 身高测量不正确。 解决方法是测量ListView Adapter的getView()方法中的每个项目。

 @Override public View getView(int position, View view, ViewGroup parent) { ViewHolder holder; if (view == null) { . . . view.setTag(holder); } else holder = (ViewHolder)view.getTag(); . . . // measure ListView item (to solve 'ListView inside ScrollView' problem) view.measure(View.MeasureSpec.makeMeasureSpec( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); return view; } 

这段代码将解决你的问题,如果你已经在代码中实现了一个ListView。

如果您使用的是RelativeLayout作为ListView子项,则此代码返回NullPointerException。listItem.measure (0,0); ,因为RelativeLayout.And解决scheme是把你的Relativelayout在一个LinearLayout中,它会正常工作。

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

你可以很容易地把ListView放在ScrollView! 只需要以编程方式更改ListView的高度,如下所示:

  ViewGroup.LayoutParams listViewParams = (ViewGroup.LayoutParams)listView.getLayoutParams(); listViewParams.height = 400; listView.requestLayout(); 

这完美的作品!

不要在父ScrollView中做任何事情。 只有这样做到子ListView。 一切都会完美的工作。

 mListView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mScrollView.requestDisallowInterceptTouchEvent(true); int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_UP: mScrollView.requestDisallowInterceptTouchEvent(false); break; } return false; } }); 

正如其他人已经提到的,不要在ScrollView中使用ListView。

要解决这个问题,您可以使用LinearLayout,但仍然保持整洁 – 使用适配器填充LinearLayout,与使用ListView一样

您可以将此类用作支持适配器的LinearLayoutreplace

 import android.content.Context; import android.database.DataSetObserver; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.LinearLayout; public class AdaptableLinearLayout extends LinearLayout { private BaseAdapter mAdapter; private int mItemCount = 0; private boolean mDisableChildrenWhenDisabled = false; private int mWidthMeasureSpec; private int mHeightMeasureSpec; public AdaptableLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public BaseAdapter getAdapter() { return mAdapter; } public void setAdapter(BaseAdapter adapter) { mAdapter = adapter; adapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { updateLayout(); super.onChanged(); } @Override public void onInvalidated() { updateLayout(); super.onInvalidated(); } }); updateLayout(); } private void updateLayout() { mItemCount = mAdapter.getCount(); requestLayout(); invalidate(); } /** * set size for the current View */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidthMeasureSpec = widthMeasureSpec; mHeightMeasureSpec = heightMeasureSpec; removeAllViewsInLayout(); for (int i = 0; i < mItemCount; i++) { makeAndAddView(i); } } private View makeAndAddView(int position) { View child; // Nothing found in the recycler -- ask the adapter for a view child = mAdapter.getView(position, null, this); // Position the view setUpChild(child, position); return child; } private void setUpChild(View child, int position) { ViewGroup.LayoutParams lp = child.getLayoutParams(); if (lp == null) { lp = generateDefaultLayoutParams(); } addViewInLayout(child, position, lp); // Get measure specs int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec, getPaddingTop() + getPaddingBottom(), lp.height); int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getPaddingLeft() + getPaddingRight(), lp.width); // Measure child child.measure(childWidthSpec, childHeightSpec); int childLeft; int childRight; // Position vertically based on gravity setting int childTop = getPaddingTop() + ((getMeasuredHeight() - getPaddingBottom() - getPaddingTop() - child.getMeasuredHeight()) / 2); int childBottom = childTop + child.getMeasuredHeight(); int width = child.getMeasuredWidth(); childLeft = 0; childRight = childLeft + width; child.layout(childLeft, childTop, childRight, childBottom); if (mDisableChildrenWhenDisabled) { child.setEnabled(isEnabled()); } } } 

你可以把所有的线性布局。 也就是说,创build线性布局,它将有2个孩子,scrollview和另一个线性布局。 给他们布局权重,在这里你去:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ScrollView android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="0.8"> <LinearLayout android:id="@+id/seTaskActivityRoot" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@color/white" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/taskName" /> <Spinner android:id="@+id/seTaskPrioritiesSP" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" /> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/taskTargetInNumeric" /> <Spinner android:id="@+id/seTaskUnitsSP" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" /> <TextView android:id="@+id/textView6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/newTaskCurrentStatus" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:ems="10" android:hint="@string/addTaskCurrentStatus" android:inputType="numberDecimal" /> </LinearLayout> </ScrollView> <LinearLayout android:layout_width="match_parent" android:layout_height="0dip" android:orientation="vertical" android:layout_weight="0.2"> <TextView android:id="@+id/textView8" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> <ListView android:id="@+id/logList" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout> 

你不应该使用带有ListView的ScrollView,因为ListView负责自己的垂直滚动。 最重要的是,这样做会挫败ListView中用于处理大型列表的所有重要优化,因为它有效地强制ListView显示其整个项目列表以填充由ScrollView提供的无限容器。

http://developer.android.com/reference/android/widget/ScrollView.html

更新

 <ScrollView android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="2" android:fillViewport="true" android:gravity="top" > <LinearLayout android:id="@+id/foodItemActvity_linearLayout_fragments" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > </LinearLayout> 

 <ScrollView android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="2" android:fillViewport="true" android:gravity="top" > <LinearLayout android:id="@+id/foodItemActvity_linearLayout_fragments" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > </LinearLayout> 

这里的重点是你正在设置高度为0dp(固定)

大量的研发工作完成后:

fragment_one.xml应该如下所示:

 <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/scrollViewParent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="400dip" > <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" /> <View android:id="@+id/customView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/transparent" /> </RelativeLayout> <!-- Your other elements are here --> </LinearLayout> </ScrollView> 

你的Java类的FragmentOne.java看起来像:

 private ListView listView; private View customView 

onCreateView

 listView = (ListView) rootView.findViewById(R.id.listView); scrollViewParent = (ScrollView)rootView.findViewById(R.id.scrollViewParent); customView = (View)rootView.findViewById(R.id.customView); customView.setOnTouchListener(new View.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. scrollViewParent.requestDisallowInterceptTouchEvent(true); // Disable touch on transparent view return false; case MotionEvent.ACTION_UP: // Allow ScrollView to intercept touch events. scrollViewParent.requestDisallowInterceptTouchEvent(false); return true; case MotionEvent.ACTION_MOVE: scrollViewParent.requestDisallowInterceptTouchEvent(true); return false; default: return true; } } }); 

我的要求是在ScrollView中包含一个大小相同的ListView。 我尝试了一些在这里列出的其他解决scheme,似乎没有正确的大小的ListView(太小或太less)。 以下是对我有用的东西:

  public static void expandListViewHeight(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) return; ViewGroup.LayoutParams params = listView.getLayoutParams(); listView.measure(0, 0); params.height = listView.getMeasuredHeight() * listAdapter.getCount() + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } 

希望这有助于某人。

find一个解决scheme的scrollview – > viewpager – > FragmentPagerAdapter – >片段 – >dynamic列表视图,但我不是作者。 有一些错误,但至less是有效的

 public class CustomPager extends ViewPager { private View mCurrentView; public CustomPager(Context context) { super(context); } public CustomPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mCurrentView == null) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } int height = 0; mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = mCurrentView.getMeasuredHeight(); if (h > height) height = h; heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void measureCurrentView(View currentView) { mCurrentView = currentView; this.post(new Runnable() { @Override public void run() { requestLayout(); } }); } public int measureFragment(View view) { if (view == null) return 0; view.measure(0, 0); return view.getMeasuredHeight(); } } public class MyPagerAdapter extends FragmentPagerAdapter { private List<Fragment> fragments; private int mCurrentPosition = -1; public MyPagerAdapter(FragmentManager fm) { super(fm);//or u can set them separately, but dont forget to call notifyDataSetChanged() this.fragments = new ArrayList<Fragment>(); fragments.add(new FirstFragment()); fragments.add(new SecondFragment()); fragments.add(new ThirdFragment()); fragments.add(new FourthFragment()); } @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { super.setPrimaryItem(container, position, object); if (position != mCurrentPosition) { Fragment fragment = (Fragment) object; CustomPager pager = (CustomPager) container; if (fragment != null && fragment.getView() != null) { mCurrentPosition = position; pager.measureCurrentView(fragment.getView()); } } } @Override public Fragment getItem(int position) { return fragments.get(position); } @Override public int getCount() { return fragments.size(); } } 

碎片布局可以是任何东西

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" tools:context="nevet.me.wcviewpagersample.FirstFragment"> <ListView android:id="@+id/lv1" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#991199"/> </LinearLayout> 

然后在某个地方

 lv = (ListView) view.findViewById(R.id.lv1); lv.setAdapter(arrayAdapter); setListViewHeightBasedOnChildren(lv); } public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) return; int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.UNSPECIFIED); 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, LinearLayout.LayoutParams.WRAP_CONTENT)); view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED); totalHeight += view.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); listView.requestLayout(); } 

千万不要把一个ListView放在ScrollView ! 您可以在Google上find关于该主题的更多信息。 在你的情况下,使用LinearLayout而不是ListView并以编程方式添加元素。

好的,这是我的答案。 修复ListView高度的方法已经够用了,但并不完美。 如果大部分物品的高度相同,那就很好。 但是,如果不是,那么就有一个很大的问题。 我已经尝试了很多次,当我把listItem.getMeasureHeight和listItem.getMeasuerWidth的值放到日志中的时候,我看到宽度值有很大的不同,这是所不希望的,因为同一个ListView中的所有项目都应该有相同的宽度。 那里有bug:

一些使用的度量(0,0),这实际上使视图在两个方向上都是未绑定的,并且宽度是狂放的。 一些尝试getWidth的listView,但它然后返回0,毫无意义。

当我进一步阅读Android如何渲染视图时,我意识到所有这些尝试都无法达到我search的答案,除非这些函数在视图渲染之后运行。

这次我使用ListView上的getViewTreeObserver来修复高度,然后使用addOnGlobalLayoutListener。 在这个方法里面,我声明了一个新的OnGlobalLayoutListener,其中,这次getWidth返回ListView的实际宽度。

 private void getLayoutWidth(final ListView lv, final int pad){ //final ArrayList<Integer> width = new ArrayList<Integer>(); ViewTreeObserver vto = lv.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { lv.getViewTreeObserver().removeOnGlobalLayoutListener(this); //width.add(layout.getMeasuredWidth()); int width = lv.getMeasuredWidth(); ListUtils.setDynamicHeight(lv, width, pad); } }); } public static class ListUtils { //private static final int UNBOUNDED = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); public static void setDynamicHeight(ListView mListView, int width, int pad) { ListAdapter mListAdapter = mListView.getAdapter(); mListView.getParent(); if (mListAdapter == null) { // when adapter is null return; } int height = 0; int desiredWidth = View.MeasureSpec.makeMeasureSpec(width - 2*pad, View.MeasureSpec.EXACTLY); for (int i = 0; i < mListAdapter.getCount(); i++) { View listItem = mListAdapter.getView(i, null, mListView); listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED); //listItem.measure(UNBOUNDED, UNBOUNDED); height += listItem.getMeasuredHeight() + 2*pad; Log.v("ViewHeight :", mListAdapter.getClass().toString() + " " + listItem.getMeasuredHeight() + "--" + listItem.getMeasuredWidth()); } ViewGroup.LayoutParams params = mListView.getLayoutParams(); params.height = height + (mListView.getDividerHeight() * (mListAdapter.getCount() - 1)); mListView.setLayoutParams(params); mListView.requestLayout(); } } 

值pad,是我在ListView布局中设置的填充。

如果由于某种原因,你不想使用addHeaderViewaddFooterView ,例如当你有多个列表时,一个好主意是重用ListAdapter来填充一个简单的LinearLayout所以没有滚动function。

如果你已经有了一个从ListFragment派生的完整片段,并且想用简单的LinearLayout把它转换成一个类似的片段而不需要滚动(例如把它放在ScrollView中),你可以像这样实现一个适配器片段:

 // converts listFragment to linearLayout (no scrolling) // please call init() after fragment is inflated to set listFragment to convert public class ListAsArrayFragment extends Fragment { public ListAsArrayFragment() {} private ListFragment mListFragment; private LinearLayout mRootView; // please call me! public void init(Activity activity, ListFragment listFragment){ mListFragment = listFragment; mListFragment.onAttach(activity); mListFragment.getListAdapter().registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { super.onChanged(); refreshView(); } }); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // create an empty vertical LinearLayout as the root view of this fragment mRootView = new LinearLayout(getActivity()); mRootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); mRootView.setOrientation(LinearLayout.VERTICAL); return mRootView; } // reusing views for performance // todo: support for more than one view type ArrayList<View> mViewsToReuse = new ArrayList<>(); ArrayList<View> mCurrentViews = new ArrayList<>(); // re-add views to linearLayout void refreshView(){ // remove old views from linearLayout and move them to mViewsToReuse mRootView.removeAllViews(); mViewsToReuse.addAll(mCurrentViews); mCurrentViews.clear(); // create new views for(int i=0; i<mListFragment.getListAdapter().getCount(); ++i){ View viewToReuse = null; if(!mViewsToReuse.isEmpty()){ viewToReuse = mViewsToReuse.get(mViewsToReuse.size()-1); mViewsToReuse.remove(mViewsToReuse.size()-1); } final View view = mListFragment.getListAdapter().getView(i, viewToReuse, mRootView); ViewGroup.LayoutParams oldParams = view.getLayoutParams(); view.setLayoutParams(new LinearLayout.LayoutParams(oldParams.width, oldParams.height)); final int finalI = i; // pass click events to listFragment view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mListFragment.onListItemClick(null, view, finalI, finalI); } }); mRootView.addView(view); mCurrentViews.add(view); } } 

您可能还想根据您的需要将onCreateonPauseonResume等转发到原始片段,或尝试inheritance而不是组合(但是重写某些方法,以使原始片段实际上不会附加到布局层次结构中)。 但我想尽可能地隔离原始片段,因为我们只需要提取其ListAdapter 。 如果您在onAttach调用原始片段的setListAdapter ,那可能就足够了。

下面是如何使用ListAsArrayFragment包含OriginalListFragment而不滚动。 在家长活动的onCreate

 ListAsArrayFragment fragment = (ListAsArrayFragment) getFragmentManager().findFragmentById(R.id.someFragmentId); OriginalListFragment originalFragment = new OriginalListFragment(); fragment.init(this, originalFragment); // now access originalFragment.getListAdapter() to modify list entries // and remember to call notifyDatasetChanged() 

find一个解决scheme的scrollview – > viewpager – > FragmentPagerAdapter – >片段 – >dynamic列表视图,但我不是作者。

 public class CustomPager extends ViewPager { private View mCurrentView; public CustomPager(Context context) { super(context); } public CustomPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mCurrentView == null) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } int height = 0; mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int h = mCurrentView.getMeasuredHeight(); if (h > height) height = h; heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void measureCurrentView(View currentView) { mCurrentView = currentView; this.post(new Runnable() { @Override public void run() { requestLayout(); } }); } public int measureFragment(View view) { if (view == null) return 0; view.measure(0, 0); return view.getMeasuredHeight(); } } public class MyPagerAdapter extends FragmentPagerAdapter { private List<Fragment> fragments; private int mCurrentPosition = -1; public MyPagerAdapter(FragmentManager fm) { super(fm);//or u can set them separately, but dont forget to call notifyDataSetChanged() this.fragments = new ArrayList<Fragment>(); fragments.add(new FirstFragment()); fragments.add(new SecondFragment()); fragments.add(new ThirdFragment()); fragments.add(new FourthFragment()); } @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { super.setPrimaryItem(container, position, object); if (position != mCurrentPosition) { Fragment fragment = (Fragment) object; CustomPager pager = (CustomPager) container; if (fragment != null && fragment.getView() != null) { mCurrentPosition = position; pager.measureCurrentView(fragment.getView()); } } } @Override public Fragment getItem(int position) { return fragments.get(position); } @Override public int getCount() { return fragments.size(); } } 

fragments layout can be anything

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" tools:context="nevet.me.wcviewpagersample.FirstFragment"> <ListView android:id="@+id/lv1" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#991199"/> </LinearLayout> 

then somewhere just

  lv = (ListView) view.findViewById(R.id.lv1); lv.setAdapter(arrayAdapter); setListViewHeightBasedOnChildren(lv); } public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) return; int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.UNSPECIFIED); 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, LinearLayout.LayoutParams.WRAP_CONTENT)); view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED); totalHeight += view.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); listView.requestLayout(); } 

using this ListView Worked for me

  package net.londatiga.android.widget; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.ListView; import android.content.Context; public class ExpandableHeightListView extends ListView { boolean expanded = false; public ExpandableHeightListView(Context context) { super(context); } public ExpandableHeightListView(Context context, AttributeSet attrs) { super(context, attrs); } public ExpandableHeightListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public boolean isExpanded() { return expanded; } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // HACK! TAKE THAT ANDROID! if (isExpanded()) { // Calculate entire height by providing a very large height hint. // But do not use the highest 2 bits of this integer; those are // reserved for the MeasureSpec mode. int expandSpec = MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); ViewGroup.LayoutParams params = getLayoutParams(); params.height = getMeasuredHeight(); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } public void setExpanded(boolean expanded) { this.expanded = expanded; } } 

and in xml

  <com.pakagename.ExpandableHeightListView android:id="@+id/expandableHeightListView" android:layout_width="match_parent" android:layout_height="wrap_content" > </com.Example.ExpandableHeightListView> 

and in MainActivity

  ExpandableHeightListView listView = new ExpandableHeightListView(this); listview=(ExpandableHeightListView)findViewById(R.id.expandableHeightListView); listView.setAdapter(adapter); //set your adaper listView.setExpanded(true); 

Refer This article for more info and also to know how to keep gridview inside scroll view

In xml:

 <com.example.util.NestedListView android:layout_marginTop="10dp" android:id="@+id/listview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:divider="@null" android:layout_below="@+id/rl_delivery_type" > </com.example.util.NestedListView> 

在Java中:

 public class NestedListView extends ListView implements View.OnTouchListener, AbsListView.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; } } 

I had a similar problem to the issue posed by the Original Poster – how to make the listview scroll inside the scrollview – and this answer solved my problem. Disable scrolling of a ListView contained within a ScrollView

I didn't call new fragments into existing layouts or anything like that, like the OP was doing, so my code would look something like this :

 <ScrollView android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="2" android:fillViewport="true" android:gravity="top" > <LinearLayout android:id="@+id/foodItemActvity_linearLayout_fragments" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/fragment_dds_review_textView_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Reviews:" android:textAppearance="?android:attr/textAppearanceMedium" /> <ListView android:id="@+id/my_listView" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout> </ScrollView> 

Basically what I am doing is checking the length of the listview before I call it and when I call it I make it into that length. In your java class use this function:

 public static void justifyListViewHeightBasedOnChildren (ListView listView) { ListAdapter adapter = listView.getAdapter(); if (adapter == null) { return; } ViewGroup vg = listView; int totalHeight = 0; for (int i = 0; i < adapter.getCount(); i++) { View listItem = adapter.getView(i, null, vg); listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams par = listView.getLayoutParams(); par.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1)); listView.setLayoutParams(par); listView.requestLayout(); } 

And call the function like this:

 justifyListViewHeightBasedOnChildren(listView); 

The result is a listview with no scrollbar, the whole length of the listview being displayed, that scrolls with the scroll bar of the scrollview.

 listView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { scrollView.requestDisallowInterceptTouchEvent(true); int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_UP: scrollView.requestDisallowInterceptTouchEvent(false); break; } return false; } }); 
  <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> </ScrollView>