scrollView中可以自由滚动的listview
直接在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的更多相关文章
- 解决android的ListView嵌套在ScrollView中不能被滚动的问题
使用滚动条容易带来一个后果,就是高度和宽度不受控制了, 之前就遇到一个已经有ScrollView的页面需要加个列表listView,然后就发现listView只看到前两行数据,下面的看不到,拉滚动条也 ...
- Android 设置ListView不可滚动 及在ScrollView中不可滚动的设置
http://m.blog.csdn.net/blog/yusewuhen/43706169 转载请注明出处: http://blog.csdn.net/androiddevelop/article/ ...
- 解决ScrollView中嵌套ListView滚动效果冲突问题
在ScrollView中嵌套使用ListView,ListView只会显示一行到两行的数据.起初我以为是样式的问题,一直在对XML文件的样 式进行尝试性设置,但始终得不到想要的效果.后来在网上查了查, ...
- 嵌套在ScrollView中的TextView控件可以自由滚动
//设置TextView控件可以自由滚动,由于这个TextView嵌套在ScrollView中,所以在OnTouch事件中通知父控件ScrollView不要干扰. mContractDesc.setO ...
- 禁用滚动视图ListView、ViewPager、ScrollView、HorizontalScrollView、WebView边界颜色渐变
禁用滚动视图ListView.ViewPager.ScrollView.HorizontalScrollView.WebView边界颜色渐变 ListView.ViewPager.ScrollView ...
- ScrollView中嵌套ListView的问题
网上关于怎样在ScrollView中嵌套ListView的讨论有很多,我大概是搜索了一下,简单总结如下: 1.不要在ScrollView中嵌套ListView a.用一个LinearLayout来代替 ...
- ScrollView中嵌套ListView时,listview高度显示的问题
方法一:直接更改listview的控件高度,动态获取(根据条目和每个条目的高度获取) 前几天因为项目的需要,要在一个ListView中放入另一个ListView,也即在一个ListView的每个Lis ...
- ScrollView中嵌套ScrollView或ListView而且内部ScrollView或ListView也可滑动
1.ScrollView中嵌套ScrollView而且内部ScrollView也可滑动 (1)ScrollView继承类 public class InnerScrollView extends Sc ...
- ListView在ScrollView中不显示全部的问题
在实际应用中,我们可能会遇到把ListView放到ScrollView中的情况,在这种情况下,ListView的滑动属性与ScrollView的滑动出现冲突,从而ListView只显示一项.这里提供一 ...
随机推荐
- 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 ...
- Git & GitHub
使用 Git 和 GitHub 有一段时间了,总结下经验. 起初接触 Git 是先遇到 GitHub 的,当时傻傻分不清这两者的区别,毕竟名字都那么像,刚开始只想用酷酷的方法 clone 代码(SSH ...
- 使用Word发表博客
使用浏览器编辑博客,会让你感到非常不方便,如果在没有网络的时候,就不能打开编辑器页面了,只能先写在word或其他编辑软件中.可以设置word使用word编辑并直接发布到博客. 文件 - 新 ...
- String Mybatis 多数据源配置
做项目用到了多数据源的配置,有时候不用就忘记了,自己做下备份以防止忘记. 在配置文件中: <bean id="ds1" class="org.apache.comm ...
- Win环境下的文件读写
在win环境下,有许多方法可以对文件进行读写操作,如MFC 中的CFile类,及一些开源的项目如QT中的QFile.开源的好得是可以多平台,而MFC只是微软自家的东西,对于想写跨平台的人,最好不用MF ...
- 谈谈eclipse使用技巧
俗话说的好啊,“工于利启事,必先善其器”,如果说你的编程功底是一个枪法的话,那么强大的eclipse就是android战士们最好的武器. 这里,我们来总结eclipse的使用技巧,从而使我们的编程达到 ...
- How to address this problem?
root# cmake .. No problem. root# make [ 63%] Linking CXX shared module collisionperceptor.so/usr/bin ...
- linux密码的更改
找到UTF-8,在后面空格后输入init=/bin/sh 然后CHRL+X启动 进入到这个界面,输入mount -o remount,rw / 再输入touch / .autorelabel ,然后 ...
- Hive的内表和外表以及分区表
1. 内表和外表的区别 内表和外表之间是通过关键字EXTERNAL来区分.删除表时: 内表:在删除时,既删除内表的元数据,也删除内表的数据 外表:删除时,仅仅删除外表的元数据. CREATE [EXT ...
- ASP.net封装
设计如下: 代码: using System; using System.IO; public partial class 四则运算 : System.Web.UI.Page { protected ...