直接在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. Fake chat script for website download

    Are you searching for free fake webchat script then you are at the right place go get download your ...

  2. Git & GitHub

    使用 Git 和 GitHub 有一段时间了,总结下经验. 起初接触 Git 是先遇到 GitHub 的,当时傻傻分不清这两者的区别,毕竟名字都那么像,刚开始只想用酷酷的方法 clone 代码(SSH ...

  3. 使用Word发表博客

        使用浏览器编辑博客,会让你感到非常不方便,如果在没有网络的时候,就不能打开编辑器页面了,只能先写在word或其他编辑软件中.可以设置word使用word编辑并直接发布到博客.   文件 - 新 ...

  4. String Mybatis 多数据源配置

    做项目用到了多数据源的配置,有时候不用就忘记了,自己做下备份以防止忘记. 在配置文件中: <bean id="ds1" class="org.apache.comm ...

  5. Win环境下的文件读写

    在win环境下,有许多方法可以对文件进行读写操作,如MFC 中的CFile类,及一些开源的项目如QT中的QFile.开源的好得是可以多平台,而MFC只是微软自家的东西,对于想写跨平台的人,最好不用MF ...

  6. 谈谈eclipse使用技巧

    俗话说的好啊,“工于利启事,必先善其器”,如果说你的编程功底是一个枪法的话,那么强大的eclipse就是android战士们最好的武器. 这里,我们来总结eclipse的使用技巧,从而使我们的编程达到 ...

  7. How to address this problem?

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

  8. linux密码的更改

    找到UTF-8,在后面空格后输入init=/bin/sh  然后CHRL+X启动 进入到这个界面,输入mount -o remount,rw / 再输入touch / .autorelabel ,然后 ...

  9. Hive的内表和外表以及分区表

    1. 内表和外表的区别 内表和外表之间是通过关键字EXTERNAL来区分.删除表时: 内表:在删除时,既删除内表的元数据,也删除内表的数据 外表:删除时,仅仅删除外表的元数据. CREATE [EXT ...

  10. ASP.net封装

    设计如下: 代码: using System; using System.IO; public partial class 四则运算 : System.Web.UI.Page { protected ...