ScrollView和ListView嵌套ListView显示不全问题
2017-05-15 22:47
288 查看
不知道大家在使用ScrollView嵌套ListView的过程中有没有发现过这样一个问题,那就是ScrollView嵌套ListView的时候无论我们怎么设置ListView的宽和高,ListView都会显示不全,并且大家有没有发现它只会显示ListView的一个条目。
那么为什么会出现这个问题,同时这个问题又是怎么处理的,别急先听我慢慢道来。
首先我们先看一下,ScrollView和ListView嵌套显示不全,是怎么显示的呢。看看是不是和你遇到的情况是否是一样的呢?
请原谅我不会发动态图,但是我的ListView有10个条目但是在这里确只是显示了一个条目。
那么在讲怎么处理这个问题之前,先讲一下为什么会出现这个问题,因为只有当我们只有知道为什么会出现这个问题,我们才能找出解决这个问题当方法。
做过自定义View的应该都会知道在自定义VIew的过程中其实有一个方法onMeasure(),他的作用就是进行测量,通俗点讲onMeasure()方法就是决定该控件的宽度和高度,因为ScrollView和ListVIew其实也是一个自定义的View,只不过他是google工程师自定义的控件,所以我们可以看官方ScrollView和ListView中 onMeasure()方法
首先先看一下ScrollView中的onMeasure()方法,在ScrollView中有一个方法
我们可以发现它给他的子VIew传递的模式为MeasureSpec.UNSPECIFIED也就是有多大取多大。
然后我们在看看ListView中的onMeasure()方法是怎么写的
代码是不是很多,没关系,我把他重要的一个判断拿了出来
上面是这样判断的如果ListVIew的测量模式为 MeasureSpec.UNSPECIFIED那么ListVIew的高度就是他的top+他一个条目的高度+bottom
好了我这里总结一下为什么ListView和ScrollView嵌套会显示不全
ScrollView在给他的子View传测量模式的时候会传MeasureSpec.UNSPECIFIED.而在ListView中他在确定ListView的高度的时候,会进行判断,如果他的测量模式为MeasureSpec.UNSPECIFIED他的高度只是一个ListVIew的条目,所以他才会显示不全
然后在来说说怎么处理这个问题,处理他的思路就是重新测量ListView的高度,这里我说一下我的处理思路,我的思路就是不让ListView的 onMeasure()方法中的判断进入
中
我们可以自定义一个类,然后继承ListView重写onMeasure()方法
这里我写出我自己onMeasure()里面的实现方式
我在这里讲一下为什么要这样写
首先讲一下makeMeasureSpec(Integer.MA
b5f1
X_VALUE >> 2, MeasureSpec.AT_MOST);里面的两个参数,一个是32位的Int类型的尺寸,第二个参数是时一个测量模式,第二个参数很好理解,第一个参数他前两位代表的是测量模式,其他位代表尺寸大小。
然后说一下为什么要给他传取Int行最大的数并且向右移动两位,向右移动两位是因为刚说了他第一个参数前两位代表测量模式。然后为什么要传int最大数呢?这里看一下下面源码我们就知道了
我们可以看到在确定ListVIew的高度的时候会有这样一个判断
也就是如果我们传入的尺寸如果小于系统计算出来的尺寸,那么就会使用我们传入的尺寸,但是我们所需要的值是系统计算出来的,所以我们在传值的过程中一定不能小于系统计算出来的值
好了这就是ScrollView嵌套ListVIew,ListView显示不全的原因.
那么为什么会出现这个问题,同时这个问题又是怎么处理的,别急先听我慢慢道来。
首先我们先看一下,ScrollView和ListView嵌套显示不全,是怎么显示的呢。看看是不是和你遇到的情况是否是一样的呢?
请原谅我不会发动态图,但是我的ListView有10个条目但是在这里确只是显示了一个条目。
那么在讲怎么处理这个问题之前,先讲一下为什么会出现这个问题,因为只有当我们只有知道为什么会出现这个问题,我们才能找出解决这个问题当方法。
做过自定义View的应该都会知道在自定义VIew的过程中其实有一个方法onMeasure(),他的作用就是进行测量,通俗点讲onMeasure()方法就是决定该控件的宽度和高度,因为ScrollView和ListVIew其实也是一个自定义的View,只不过他是google工程师自定义的控件,所以我们可以看官方ScrollView和ListView中 onMeasure()方法
首先先看一下ScrollView中的onMeasure()方法,在ScrollView中有一个方法
@Override protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int usedTotal = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed; final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal), MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
我们可以发现它给他的子VIew传递的模式为MeasureSpec.UNSPECIFIED也就是有多大取多大。
然后我们在看看ListView中的onMeasure()方法是怎么写的
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Sets up mListPadding super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int childWidth = 0; int childHeight = 0; int childState = 0; mItemCount = mAdapter == null ? 0 : mAdapter.getCount(); if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED)) { final View child = obtainView(0, mIsScrap); // Lay out child directly against the parent measure spec so that // we can obtain exected minimum width and height. measureScrapChild(child, 0, widthMeasureSpec, heightSize); childWidth = child.getMeasuredWidth(); childHeight = child.getMeasuredHeight(); childState = combineMeasuredStates(childState, child.getMeasuredState()); if (recycleOnMeasure() && mRecycler.shouldRecycleViewType( ((LayoutParams) child.getLayoutParams()).viewType)) { mRecycler.addScrapView(child, 0); } } if (widthMode == MeasureSpec.UNSPECIFIED) { widthSize = mListPadding.left + mListPadding.right + childWidth + getVerticalScrollbarWidth(); } else { widthSize |= (childState & MEASURED_STATE_MASK); } if (heightMode == MeasureSpec.UNSPECIFIED) { heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2; } ... setMeasuredDimension(widthSize, heightSize); mWidthMeasureSpec = widthMeasureSpec; }
代码是不是很多,没关系,我把他重要的一个判断拿了出来
if (heightMode == MeasureSpec.UNSPECIFIED) { heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2; }
上面是这样判断的如果ListVIew的测量模式为 MeasureSpec.UNSPECIFIED那么ListVIew的高度就是他的top+他一个条目的高度+bottom
好了我这里总结一下为什么ListView和ScrollView嵌套会显示不全
ScrollView在给他的子View传测量模式的时候会传MeasureSpec.UNSPECIFIED.而在ListView中他在确定ListView的高度的时候,会进行判断,如果他的测量模式为MeasureSpec.UNSPECIFIED他的高度只是一个ListVIew的条目,所以他才会显示不全
然后在来说说怎么处理这个问题,处理他的思路就是重新测量ListView的高度,这里我说一下我的处理思路,我的思路就是不让ListView的 onMeasure()方法中的判断进入
if (heightMode == MeasureSpec.UNSPECIFIED) { heightSize = mListPadding.top + mListPadding.bottom + childHeight + getVerticalFadingEdgeLength() * 2; }
中
我们可以自定义一个类,然后继承ListView重写onMeasure()方法
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int i = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, i); }
这里我写出我自己onMeasure()里面的实现方式
我在这里讲一下为什么要这样写
首先讲一下makeMeasureSpec(Integer.MA
b5f1
X_VALUE >> 2, MeasureSpec.AT_MOST);里面的两个参数,一个是32位的Int类型的尺寸,第二个参数是时一个测量模式,第二个参数很好理解,第一个参数他前两位代表的是测量模式,其他位代表尺寸大小。
然后说一下为什么要给他传取Int行最大的数并且向右移动两位,向右移动两位是因为刚说了他第一个参数前两位代表测量模式。然后为什么要传int最大数呢?这里看一下下面源码我们就知道了
final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition, int maxHeight, int disallowPartialChildPosition) { final ListAdapter adapter = mAdapter; if (adapter == null) { return mListPadding.top + mListPadding.bottom; } // Include the padding of the list int returnedHeight = mListPadding.top + mListPadding.bottom; final int dividerHeight = mDividerHeight; // The previous height value that was less than maxHeight and contained // no partial children int prevHeightWithoutPartialChild = 0; int i; View child; // mItemCount - 1 since endPosition parameter is inclusive endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition; final AbsListView.RecycleBin recycleBin = mRecycler; final boolean recyle = recycleOnMeasure(); final boolean[] isScrap = mIsScrap; for (i = startPosition; i <= endPosition; ++i) { child = obtainView(i, isScrap); measureScrapChild(child, i, widthMeasureSpec, maxHeight); if (i > 0) { // Count the divider for all but one child returnedHeight += dividerHeight; } // Recycle the view before we possibly return from the method if (recyle && recycleBin.shouldRecycleViewType( ((LayoutParams) child.getLayoutParams()).viewType)) { recycleBin.addScrapView(child, -1); } returnedHeight += child.getMeasuredHeight(); if (returnedHeight >= maxHeight) { // We went over, figure out which height to return. If returnedHeight > maxHeight, // then the i'th position did not fit completely. return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1) && (i > disallowPartialChildPosition) // We've past the min pos && (prevHeightWithoutPartialChild > 0) // We have a prev height && (returnedHeight != maxHeight) // i'th child did not fit completely ? prevHeightWithoutPartialChild : maxHeight; } if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) { prevHeightWithoutPartialChild = returnedHeight; } } // At this point, we went through the range of children, and they each // completely fit, so return the returnedHeight return returnedHeight; }
我们可以看到在确定ListVIew的高度的时候会有这样一个判断
if (returnedHeight >= maxHeight) { // We went over, figure out which height to return. If returnedHeight > maxHeight, // then the i'th position did not fit completely. return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1) && (i > disallowPartialChildPosition) // We've past the min pos && (prevHeightWithoutPartialChild > 0) // We have a prev height && (returnedHeight != maxHeight) // i'th child did not fit completely ? prevHeightWithoutPartialChild : maxHeight; }
也就是如果我们传入的尺寸如果小于系统计算出来的尺寸,那么就会使用我们传入的尺寸,但是我们所需要的值是系统计算出来的,所以我们在传值的过程中一定不能小于系统计算出来的值
好了这就是ScrollView嵌套ListVIew,ListView显示不全的原因.
相关文章推荐
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- Android开发 详解嵌套ListView、ScrollView布局显示不全的问题
- 自定义控件之解决ScrollView里面嵌套ListView显示不全的问题
- [详解嵌套ListView、ScrollView布局显示不全的问题]
- ScrollView中嵌套ListView或ExpandableListView时显示不全的问题
- 详解嵌套ListView、ScrollView布局显示不全的问题
- 详解嵌套ListView、ScrollView布局显示不全的问题
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- 关于在ScrollView中嵌套ListView,ListView显示不全的问题
- 解决ScrollView 嵌套 ListView GridView显示不全,以及默认不在ScrollView顶部的问题
- 解决ScrollView下嵌套ListView、GridView显示不全的问题(冲突)
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- 解决ScrollView嵌套ListView或ListView嵌套ListView,listview显示不全的问题
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- 解决ScrollView下嵌套ListView、GridView显示不全的问题
- 解决ScrollView内嵌套ListView时显示不全的问题
- scrollview嵌套listview 数据显示不全 问题处理方式集合
- ScrollView 下嵌套 ListView 或 GridView 冲突显示不全问题
- Android学习 之 问题&解答 ScrollView中嵌套ListView时显示不全的简便解决方案
- 解决ScrollView下嵌套ListView、GridView显示不全的问题