Scrolview 嵌套ListView 导致ListView条目不能展开的问题及原理详解
来源:互联网 发布:2016网络神曲排行榜 编辑:程序博客网 时间:2024/05/02 05:40
以前开发遇到ScrollView嵌套ListView的问题,虽然一脸懵逼啥也不懂,但是只要Google,问题总是可以解决,但是如果不深究只是拷贝的话,那么以后遇到还是一脸懵逼,今天无意中遇到了有人问这样的问题,那么就我就来解答一下部分人的疑惑。
1、 Question——问题
ScrollView嵌套ListView的时候ListView的条目只显示一个,而且快速滑动的时候也会出问题。
2、 How to do—我们该怎么做
我们Google到的这类问题的解决方法一般是Override ListView的onMeasure(int widthMeasureSpec,int heightMeasureSpec)方法,代码如下:
public class ListViewForScrollView extends ListView { public ListViewForScrollView(Context context) { super(context); } public ListViewForScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public ListViewForScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override /** * 重写该方法,达到使ListView适应ScrollView的效果 */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); }}
3、Why :我们为什么要这么写呢?
要想知道我们为什么这么写,就得先知道为什么会出现这样的问题,看完各种各样的说话以后,再经过我们的大脑处理,我们可以确定,原来是由于ScrollView事件消费以及ListView的高度不确定导致的,那么为什么我们通过上面的简单的代码就搞定了呢?让我们走进MeasureSpec源码去一探究竟。。。
/** * A MeasureSpec encapsulates the layout requirements passed from parent to child. * Each MeasureSpec represents a requirement for either the width or the height. * A MeasureSpec is comprised of a size and a mode. There are three possible * modes: * <dl> * <dt>UNSPECIFIED</dt> * <dd> * The parent has not imposed any constraint on the child. It can be whatever size * it wants. * </dd> * * <dt>EXACTLY</dt> * <dd> * The parent has determined an exact size for the child. The child is going to be * given those bounds regardless of how big it wants to be. * </dd> * * <dt>AT_MOST</dt> * <dd> * The child can be as large as it wants up to the specified size. * </dd> * </dl> * * MeasureSpecs are implemented as ints to reduce object allocation. This class * is provided to pack and unpack the <size, mode> tuple into the int. */ public static class MeasureSpec { private static final int MODE_SHIFT = 30; private static final int MODE_MASK = 0x3 << MODE_SHIFT; /** @hide */ @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) @Retention(RetentionPolicy.SOURCE) public @interface MeasureSpecMode {} /** * Measure specification mode: The parent has not imposed any constraint * on the child. It can be whatever size it wants. */ public static final int UNSPECIFIED = 0 << MODE_SHIFT; /** * Measure specification mode: The parent has determined an exact size * for the child. The child is going to be given those bounds regardless * of how big it wants to be. */ public static final int EXACTLY = 1 << MODE_SHIFT; /** * Measure specification mode: The child can be as large as it wants up * to the specified size. */ public static final int AT_MOST = 2 << MODE_SHIFT; /** * Creates a measure specification based on the supplied size and mode. * * The mode must always be one of the following: * <ul> * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> * </ul> * * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's * implementation was such that the order of arguments did not matter * and overflow in either value could impact the resulting MeasureSpec. * {@link android.widget.RelativeLayout} was affected by this bug. * Apps targeting API levels greater than 17 will get the fixed, more strict * behavior.</p> * * @param size the size of the measure specification * @param mode the mode of the measure specification * @return the measure specification based on size and mode */ public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode) { if (sUseBrokenMakeMeasureSpec) { return size + mode; } else { return (size & ~MODE_MASK) | (mode & MODE_MASK); } } /** * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED * will automatically get a size of 0. Older apps expect this. * * @hide internal use only for compatibility with system widgets and older apps */ public static int makeSafeMeasureSpec(int size, int mode) { if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { return 0; } return makeMeasureSpec(size, mode); } /** * Extracts the mode from the supplied measure specification. * * @param measureSpec the measure specification to extract the mode from * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, * {@link android.view.View.MeasureSpec#AT_MOST} or * {@link android.view.View.MeasureSpec#EXACTLY} */ @MeasureSpecMode public static int getMode(int measureSpec) { //noinspection ResourceType return (measureSpec & MODE_MASK); } /** * Extracts the size from the supplied measure specification. * * @param measureSpec the measure specification to extract the size from * @return the size in pixels defined in the supplied measure specification */ public static int getSize(int measureSpec) { return (measureSpec & ~MODE_MASK); } static int adjust(int measureSpec, int delta) { final int mode = getMode(measureSpec); int size = getSize(measureSpec); if (mode == UNSPECIFIED) { // No need to adjust size for UNSPECIFIED mode. return makeMeasureSpec(size, UNSPECIFIED); } size += delta; if (size < 0) { Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + ") spec: " + toString(measureSpec) + " delta: " + delta); size = 0; } return makeMeasureSpec(size, mode); } /** * Returns a String representation of the specified measure * specification. * * @param measureSpec the measure specification to convert to a String * @return a String with the following format: "MeasureSpec: MODE SIZE" */ public static String toString(int measureSpec) { int mode = getMode(measureSpec); int size = getSize(measureSpec); StringBuilder sb = new StringBuilder("MeasureSpec: "); if (mode == UNSPECIFIED) sb.append("UNSPECIFIED "); else if (mode == EXACTLY) sb.append("EXACTLY "); else if (mode == AT_MOST) sb.append("AT_MOST "); else sb.append(mode).append(" "); sb.append(size); return sb.toString(); }}
代码也不多,100多行,最开始是对MeasureSpec这个类的介绍,大概就是说这个类封装了父布局传递给子布局的一些要求,一个MeasureSpec类需要两个参数,一个是size ,一个是mode,这里给出了三种mode:
1. UNSPECIFIED:我们看注释可以了解到,意思就是说,老子没要求,儿子爱咋滴咋滴
2. EXACTLY:意思就是说,老子是确定的大小,儿子也必须是确定的大小
3. AT_MOST:意思就是说,老子给个最大值,儿子愿意多大就多大,但是别超过老子
然后有3个方法比较重要:
1.public static int makeMeasureSpec(int size, int mode) ,这个方法的作用是根据大小和模式来生成一个int值,这个int值封装了模式和大小信息
2.public static int getMode(int measureSpec),这个方法的作用是通过一个int值来获取里面的模式信息
3.public static int getSize(int measureSpec),这个方法的作用是通过一个int值来获取里面的大小信息
在Android里面,一个控件所占的模式和大小是通过一个整数int来表示的,这里很多同学就疑惑了,一个int值是怎么来表示模式的大小的,这里来看一张图片:
private static final int MODE_SHIFT = 30;
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
public static final int EXACTLY = 1 << MODE_SHIFT;
public static final int AT_MOST = 2 << MODE_SHIFT;
不确定模式是0左移30位,也就是int类型的最高两位是00
精确模式是1左移30位,也就是int类型的最高两位是01
最大模式是是2左移30位,也就是int类型的最高两位是10
现在我们知道了,我们肯定是要AT_MOST这个模式了,但是值我们要多大呢?当然是要最大值了,最大值该怎么表示呢?前面我们说过了,Android控件封装了int,用int的最高的两位表示模式,其余的位数表示控件的大小,那么我们要最大值该怎么表示呢?自然就是Integer.MAX_VALUE >> 2这个了,所以最后的表达是:MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2
, MeasureSpec.AT_MOST);,如果不懂移位运行的,不用担心,本博主都给你准备好学习的资料了,点进去,看明白就o了:http://blog.csdn.net/HayJohn/article/details/61929889
- Scrolview 嵌套ListView 导致ListView条目不能展开的问题及原理详解
- 从源码分析Scrolview 嵌套ListView 导致ListView条目不能展开的原理
- ScrolView 嵌套ListView 显示不全的问题
- 解决drawerlayout嵌套listview 导致listview不能滑动的问题
- 详解:scrollview嵌套listview,而listview的item中是webview,导致listview不能在scrollview完全伸展开的问题
- ExpandableListView嵌套ListView导致ListView不能完全显示数据的问题
- listView条目不能点击问题
- listview嵌套listview,底部的listview不能滑动问题
- listview嵌套gridview 条目里面gridview显示不全的问题
- android开发游记:ScrollView嵌套ListView,ListView完全展开及makeMeasureSpec测量机制原理分析
- scrollView中嵌套ListView,ListView不能滚动的问题
- 解决scrolview 中含有listview问题
- ListView嵌套ListView的问题
- Android控件listView条目不能点击问题
- listView 条目错乱的问题
- ScrollView嵌套全部展开显示的ListView
- ListView嵌套EditText导致软键盘闪退的问题
- ScrollView中嵌套ListView/GridView导致的问题总结
- SDUT 3769 分割 超大数据加一位数 比较大小
- Flume-ng源码解析之Channel组件
- 在maven项目移植时,Maven Dependencies不见了!!!
- 设计模式——Java动态代理
- C语言最简开发环境(续一)
- Scrolview 嵌套ListView 导致ListView条目不能展开的问题及原理详解
- 屏幕色温
- 【Coursera】编程题 Collinear Points
- java 文件读取
- 技术积累
- Redis使用详解之redhat系统上安装redis-3.2.8
- HDU 3047 Zjnu Stadium(带权并查集)
- leetcode解题之121 # Best Time to Buy and Sell Stock
- Matlab中几种括号的区别