让listview在scrollview中自由滑动
来源:互联网 发布:淘宝浏览app赚佣金 编辑:程序博客网 时间:2024/05/21 10:38
总有人我listview嵌套scrollview怎么弄。一问就是半天,太耗时,所以写个博客也算是自己总结一下。
目标
scrollview嵌套listview,可以自由的定义listview的大小,而不是展示全部listview。
让listview在scrollview中自由滑动。
当listview滑动到顶端或底端的时候,让scrollview开始滑动
直接上图看效果好了:
代码也很简单 直接上代码
<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="wang.com.scrollholdlistview.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/activity_vertical_margin" android:text="Hello World!" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/activity_vertical_margin" android:text="Hello World!" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/activity_vertical_margin" android:text="Hello World!" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/activity_vertical_margin" android:text="Hello World!" android:textSize="30sp" /> <wang.com.scrollholdlistview.MyListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="400dp" android:background="@color/colorAccent"></wang.com.scrollholdlistview.MyListView> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/activity_vertical_margin" android:text="Hello World!" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/activity_vertical_margin" android:text="Hello World!" android:textSize="30sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/activity_vertical_margin" android:text="Hello World!" android:textSize="30sp" /> <wang.com.scrollholdlistview.MyListView android:id="@+id/lv1" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorAccent"> </wang.com.scrollholdlistview.MyListView> </LinearLayout></ScrollView>
package wang.com.scrollholdlistview;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.ListView;/** * 创建日期: 16/4/3 下午9:55 * 作者:wanghao * 描述: */public class MyListView extends ListView { private static final String TAG = "MyListView"; public MyListView(Context context) { this(context, null); } public MyListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int defaultsize=measureHight(Integer.MAX_VALUE >> 2, heightMeasureSpec); int expandSpec = MeasureSpec.makeMeasureSpec(defaultsize, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } private int measureHight(int size, int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { Log.i(TAG, "exactly" ); result = specSize; } else { result = size;//最小值是200px ,自己设定 if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } Log.i(TAG, "specMode:"+specMode+"--result:"+result ); } return result; } /** * 改listview滑到底端了 * * @return */ public boolean isBottom() { int firstVisibleItem = getFirstVisiblePosition();//屏幕上显示的第一条是list中的第几条 int childcount = getChildCount();//屏幕上显示多少条item int totalItemCount = getCount();//一共有多少条 if ((firstVisibleItem + childcount) >=totalItemCount) { return true; } return false; } /** * 改listview在顶端 * * @return */ public boolean isTop() { int firstVisibleItem = getFirstVisiblePosition(); if (firstVisibleItem ==0) { return true; } return false; } float down = 0; float y; @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: down = event.getRawY(); getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: y = event.getRawY(); if (isTop()) { if (y - down > 1) {// 到顶端,向下滑动 把事件教给父类 getParent().requestDisallowInterceptTouchEvent(false); } else { // 到顶端,向上滑动 把事件拦截 由自己处理 getParent().requestDisallowInterceptTouchEvent(true); } } if (isBottom()) { if (y - down > 1) {// 到底端,向下滑动 把事件拦截 由自己处理 getParent().requestDisallowInterceptTouchEvent(true); } else {// 到底端,向上滑动 把事件教给父类 getParent().requestDisallowInterceptTouchEvent(false); } } break; default: break; } return super.dispatchTouchEvent(event); }}
上面代码直接用就可以啦。
那么下面说下好多人遇到过的疑惑
- 为什么这么写就能避免嵌套问题呢
下面代码是网上流传最多的
@Overridepublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int expandSpec = MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec);}
这样写呢有个弊端,就是 在scrollview里面展示了 listview的全部内容。有100条就显示了100条。
Integer.MAX_VALUE >> 2这个呢就是一个值。让你的listview最大值是多大。你可以写成65535,或者其他数值。为什么用 MeasureSpec.AT_MOST呢?
看下super里面
@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;//获取有多少个item final AbsListView.RecycleBin recycleBin = mRecycler; final boolean recyle = recycleOnMeasure(); final boolean[] isScrap = mIsScrap;//遍历所有item并且 获取到 所有item的整体高度 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();//如果item的高度大于咱们赋值的高度也就是Integer.MAX_VALUE >> 2 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 如果是大于就用自己item整体的高度作为listview的高度 : maxHeight; 如果是等于那么久用 我们赋值的高度 }//如果item的高度 不大于等于 默认值 那么久显示他自己的高度了 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; }
所以我们赋值的Integer.MAX_VALUE >> 2只是一个参考值,你想写多少就是多少。
但是那样写有个弊端就是在xml里面写的高度 就没用了。所以我们就这么写了
@Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int defaultsize=measureHight(Integer.MAX_VALUE >> 2, heightMeasureSpec); int expandSpec = MeasureSpec.makeMeasureSpec(defaultsize, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } private int measureHight(int size, int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { Log.i(TAG, "exactly" ); result = specSize; } else { result = size;//最小值是200px ,自己设定 if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } Log.i(TAG, "specMode:"+specMode+"--result:"+result ); } return result; }
这样的话就是如果 xml里面是wrap_content的话 就显示所有item的高度。如果是设置了 高度值 比如是400dp。那么listview显示的高度就是400dp。
为什么那么些 请戳这尼自定义view,viewgroup的onMeasure 方法
那么问题又来了。
如果显示400dp的高度。listview就没法全部显示了。
所以就不能让scrollview拦截事件,要让该事件传递到listview,并且处理。 一行代码就搞定
getParent().requestDisallowInterceptTouchEvent(true); true:就是拦截此事件 false:不拦截此事件,让父类处理
剩下的就只是当listview滑动到顶端和底端 listview就拦截该事件了。代码里已经体现的很简单了。
尊重原创:http://blog.csdn.net/wanghao200906/article/details/51084975
代码在这里
最近太忙了。发个福利安慰一下自己
- 让listview在scrollview中自由滑动
- 让listview在scrollview中自由滑动
- 解决ListView在ScrollView中滑动冲突
- listview在scrollview中自行滑动(滑动冲突)
- 解决ListView在ScrollView中滑动冲突的问题
- 解决水平ListView在ScrollView中出现的滑动冲突
- 自定义listview/gridview实现在scrollview中滑动
- 解决ListView嵌套在ScrollView中滑动冲突问题
- 实现水平ListView,并且解决水平ListView在ScrollView中Listview中出现的滑动冲突
- ScrollView 中嵌入ListView 控件 滑动ListView
- 重写ListView、GridView让其在ScrollView中完整显示
- 实现水平listview,而且解决水平listview在scrollview中出现的滑动冲突
- 安卓学习笔记---实现两个ListView或者GridView在Scrollview中同时滑动,实现ScrollView滑动到顶部
- ScrollView中嵌套ListView 滑动冲突
- ScrollView中嵌套ListView滑动问题
- 在ScrollView中嵌套ListView
- 在ScrollView中使用ListView
- 在ScrollView中嵌套ListView
- 软件工程需求分析
- java web程序升级jsp页面缓存无法显示最新的内容
- .NET 通过代码创建XML文档
- 动态规划经典问题Java实现
- 【笔记】 《js权威指南》- 第15章 脚本化文档 - 15.3 - 15.4
- 让listview在scrollview中自由滑动
- node.js中mysql的简单使用
- java服务器学习
- 使用tcpdump统计andorid流量
- 乐观锁与悲观锁区别
- json 解析 数组中的对象
- 【笔试/面试】—— 有向无环图(DAG)的最短路径问题(动态规划)
- namespace中配iptables规则注意事项
- HDU 4848 Wow! Such Conquering! 深搜+强剪枝