直接在scrollView中写listview等可滚动控件会出现子控件高度计算的问题,为了解决这个问题,找到的方案是重写listview中的onmeasure方法:

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

但是这样造成的问题是listview会显示出所有的内容,如果listview的数量有100条,那么就很酸爽了.其实说到底还是listview不能滚动,只要让listview可以滚动,问题可以完美解决.

    @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);

     ....
if (heightMode == MeasureSpec.AT_MOST) {
// TODO: after first layout we should maybe start at the first visible position, not 0
heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
} setMeasuredDimension(widthSize, heightSize); mWidthMeasureSpec = widthMeasureSpec;
}

再来看看measureHeightOfChildren是怎么实现的

    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 > 0) && mDivider != null) ? mDividerHeight : 0;
// 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的onmeasure方法中判断一下,如果listview是写死的高度,那么就将这个死的高度作为listview的最大高度值传给super.measure();否则,传入INTEGER.MAX_VALUE >> 2,这样一来,如果xml文件里面的listview的高度是wrapconten,那么就会显示所有的listview,如果写死,那么listview就是写死的高度,接下来的问题是,如果listview的高度是死的,怎么让listview自由滚动,很简单,android系统提供给我们一个方法,可以拦截或者不拦截touch事件.

getParent().requestDisallowInterceptTouchEvent(true);
true:touch事件由子控件处理
false:touch事件由父类处理

最后附上完整代码:

package com.bbd.picturesel.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView; /**
* Created by penny on 2016/4/25.
*/
public class ScrollListView extends ListView { public ScrollListView(Context context) {
this(context, null);
} public ScrollListView(Context context, AttributeSet attributeSet) {
this(context, attributeSet, 0);
} public ScrollListView(Context context, AttributeSet attributeSet, int defStyleAttr) {
super(context, attributeSet, defStyleAttr);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int maxsize = measureHeight(Integer.MAX_VALUE >> 2, heightMeasureSpec);
int expandSpec = MeasureSpec.makeMeasureSpec(maxsize, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
} /**
* @param defaultMaxSize listview的最大高度默认值
* @param heightMeasureSpec
* @return 计算之后的listview的最大高度
*/
private int measureHeight(int defaultMaxSize, int heightMeasureSpec) {
int result = 0;
int measureMode = MeasureSpec.getMode(heightMeasureSpec);
int measureSize = MeasureSpec.getSize(heightMeasureSpec);
if (measureMode == MeasureSpec.EXACTLY) {
result = measureSize;
} else {
result = defaultMaxSize;
if (measureMode == MeasureSpec.AT_MOST) {
result = Math.min(defaultMaxSize, measureSize);
} }
return result;
} /**
* 判断listview是否处于最底部
*
* @return
*/
private boolean isBottom() {
boolean isBottom = false;
int firstItemId = getFirstVisiblePosition();
int currentScreenCount = getChildCount();
int total = getCount();
if (firstItemId + currentScreenCount >= total) {
isBottom = true;
}
return isBottom;
} /**
* 判断listview是否处于最顶部
*
* @return
*/
private boolean isTop() {
int firstVisiblePosition = getFirstVisiblePosition();
if (firstVisiblePosition == 0) {
return true;
} else
return false;
} private float y = 0;
private float touchDown = 0; @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
touchDown = ev.getRawY();
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
y = ev.getRawY();
if (isTop() && isBottom()) {//listview已全部显示,不自由滚动
getParent().requestDisallowInterceptTouchEvent(false);
} else if (isTop()) {//listview目前在最上部
if (y - touchDown > 1) {
getParent().requestDisallowInterceptTouchEvent(false);
} else {
getParent().requestDisallowInterceptTouchEvent(true);
}
} else if (isBottom()) {//listview目前在最下部
if (y - touchDown > 1) {//由listview处理touch事件
getParent().requestDisallowInterceptTouchEvent(true);
} else {//由父控件处理touch事件
getParent().requestDisallowInterceptTouchEvent(false);
}
}
break;
default:
break;
} return super.dispatchTouchEvent(ev);
}
}

感谢原作者:http://blog.csdn.net/wanghao200906/article/details/51084975

scrollView中可以自由滚动的listview的更多相关文章

  1. 解决android的ListView嵌套在ScrollView中不能被滚动的问题

    使用滚动条容易带来一个后果,就是高度和宽度不受控制了, 之前就遇到一个已经有ScrollView的页面需要加个列表listView,然后就发现listView只看到前两行数据,下面的看不到,拉滚动条也 ...

  2. Android 设置ListView不可滚动 及在ScrollView中不可滚动的设置

    http://m.blog.csdn.net/blog/yusewuhen/43706169 转载请注明出处: http://blog.csdn.net/androiddevelop/article/ ...

  3. 解决ScrollView中嵌套ListView滚动效果冲突问题

    在ScrollView中嵌套使用ListView,ListView只会显示一行到两行的数据.起初我以为是样式的问题,一直在对XML文件的样 式进行尝试性设置,但始终得不到想要的效果.后来在网上查了查, ...

  4. 嵌套在ScrollView中的TextView控件可以自由滚动

    //设置TextView控件可以自由滚动,由于这个TextView嵌套在ScrollView中,所以在OnTouch事件中通知父控件ScrollView不要干扰. mContractDesc.setO ...

  5. 禁用滚动视图ListView、ViewPager、ScrollView、HorizontalScrollView、WebView边界颜色渐变

    禁用滚动视图ListView.ViewPager.ScrollView.HorizontalScrollView.WebView边界颜色渐变 ListView.ViewPager.ScrollView ...

  6. ScrollView中嵌套ListView的问题

    网上关于怎样在ScrollView中嵌套ListView的讨论有很多,我大概是搜索了一下,简单总结如下: 1.不要在ScrollView中嵌套ListView a.用一个LinearLayout来代替 ...

  7. ScrollView中嵌套ListView时,listview高度显示的问题

    方法一:直接更改listview的控件高度,动态获取(根据条目和每个条目的高度获取) 前几天因为项目的需要,要在一个ListView中放入另一个ListView,也即在一个ListView的每个Lis ...

  8. ScrollView中嵌套ScrollView或ListView而且内部ScrollView或ListView也可滑动

    1.ScrollView中嵌套ScrollView而且内部ScrollView也可滑动 (1)ScrollView继承类 public class InnerScrollView extends Sc ...

  9. ListView在ScrollView中不显示全部的问题

    在实际应用中,我们可能会遇到把ListView放到ScrollView中的情况,在这种情况下,ListView的滑动属性与ScrollView的滑动出现冲突,从而ListView只显示一项.这里提供一 ...

随机推荐

  1. iOS UIView上添加mp4视频

    ViewController.h文件中添加如下代码: #import <MediaPlayer/MediaPlayer.h> @property(nonatomic,retain) MPM ...

  2. Android之NDK开发(转)

    Android之NDK开发 一.NDK产生的背景 Android平台从诞生起,就已经支持C.C++开发.众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第 ...

  3. 处理GitHub不允许上传大于100M文件问题

    第一步输入命令 cd /Users/Dora/Desktop/XXX(cd后面的这个路径要换成你自己项目的路径) 第二步输入命令 git rm --cached/Users/Dora/Desktop/ ...

  4. ECMAScript6 面向对象 时钟效果

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  5. javascript 中的借鸡生蛋

    如题所说,其实指的是 js 中的内置函数和 apply 的结合使用.这种用法很讨巧,读过 jQuery 源码的小伙伴都知道,它在里面被应用的非常广泛和精妙! 梨子:找出一个数组中的最大值和最小值 普遍 ...

  6. Lyft押重注于苹果编程语言Swift

    Lyft押重注于苹果编程语言Swift 1年后获得丰厚回报BI中文站 8月22日报道 一年多以前,打车应用Lyft做出重大决定,决心押重注于苹果开发的编程语言Swift,用这种编程语言重写其所有iPh ...

  7. iOS 给NSString文字上添加横线 中间和下划线

    有时候我们需要给文字添加横线,有两种情况: 第一种是贯穿中间的横线: 横线的颜色和文字的颜色保持一致 _oldPriceLabel.text = "; _oldPriceLabel.text ...

  8. mysql连接查询和子查询

    一.连接查询 1.交叉连接 就是从一张表的一条记录去连接另一张表中的所有记录,并且保存所有的记录,其中包括两个表的所有的字段! 从结果上看,就是对两张表做笛卡尔积! 笛卡尔积也就是两个表中所有可能的连 ...

  9. leetcode 日记 162. Find Peak Element java python

    根据题目可知,输入为:一个相邻元素不相等的数列,输出为:其中一个(上)峰值的序号.并且要求时间复杂度为logn 分析:由于题目要求时间复杂度为logn,因此不能进行全部遍历.又因为只需要找到其中的一个 ...

  10. How to address this problem?

    root# cmake .. No problem. root# make [ 63%] Linking CXX shared module collisionperceptor.so/usr/bin ...