ScrollView嵌套使用ListView冲突的解决与分析

时间:2023-01-08 10:00:29

  因为ScrollView与ListView都是具有滚动条的控件,所以嵌套在一起使用的时候可能会出现事件的冲突,比如我就遇见了ListView中只显示一条数据的问题。解决的办法,就是自定义了一个ListView,重写它的onMeasure()方法:

  

 public class MyListView extends ListView {

     public MyListView(Context context) {
super(context);
// TODO Auto-generated constructor stub
} public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
} public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec); } }

MeasureSpec.makeMeasureSpec()方法是由我们给出的尺寸大小和模式,来生成一个包含这两个信息的int类型的变量。根据我们提供打大小值和模式创建一个测量值(格式)。

每次onMeasure()的时候都重新绘制高度,这样就不会只显示一条数据。

为什么会只显示一行的高度呢?这其实跟ListView的源码有关,ListView的父容器测量模式为UNSPECIFIED的时候,ListView的高度默认为一个item的高度,

ScrollView中的部分源码:

 final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.UNSPECIFIED) {
return;
}

ListView中源码如下:

 if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight +
getVerticalFadingEdgeLength() * 2;
}

原理分析:

  原理的理解是看了这篇博主的博文才理解的,写的很清楚,不明白的可以去看下:

  ScrollView嵌套ListView,ListView完全展开及makeMeasureSpec测量机制原理分析

  从上面看出,我们把高度写成了一个固定的值expandSpec,这个值得计算方法如下:

 expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);

  可以看出我们将整数类型的最大值向右移了两位作为参数传入,模式我们传入了常量MeasureSpec.AT_MOST。而为什么我们重新计算了高度值,并且还是一个这么奇葩的数值作为参数传入呢?这就跟Android中的实体测量机制相关了,android中规定,测量的值,高度或者是宽度,是作为一个int类型的数值,但不是普通的int,而是一个经过处理的int值,在view视图中,我们制定一个高度或者宽度,需要指定两个参数,一个是具体大小,另一个是测量模式,测量模式就是我们在布局中经常用到的MATCH_PARENT、WRAP_CONTENT。他们是一个int类型的常量,分别对应值:

 LayoutParams.MATCH_PARENT  对应 MeasureSpec.EXACTLY
LayoutParams.WRAP_CONTENT 对应 MeasureSpec.AT_MOST

在源码中的展示为:

 public class View implements ... {
...
public static class MeasureSpec {
private static final int MODE_SHIFT = 30; //移位位数为30
//int类型占32位,向左移位30位,用来与size和mode进行"&"运算,获取对应值。
private static final int MODE_MASK = 0x3 << MODE_SHIFT;
//向左移位30位,其值为00 + (30位0) , 即 0x0000(16进制表示)
public static final int UNSPECIFIED = 0 << MODE_SHIFT;
//向左移位30位,其值为01 + (30位0) , 即0x1000(16进制表示)
public static final int EXACTLY = 1 << MODE_SHIFT;
//向左移位30位,其值为02 + (30位0) , 即0x2000(16进制表示)
public static final int AT_MOST = 2 << MODE_SHIFT; //创建一个整形值,其高两位代表mode类型,其余30位代表长或宽的实际值。可以是WRAP_CONTENT、MATCH_PARENT或具体大小exactly size
public static int makeMeasureSpec(int size, int mode) {
return size + mode;
}
//获取模式 ,与运算
public static int getMode(int measureSpec) {
return (measureSpec & MODE_MASK);
}
//获取长或宽的实际值 ,与运算
public static int getSize(int measureSpec) {
return (measureSpec & ~MODE_MASK);
} }
...

可以看到,EXACTLY和AT_MOST的值是:

 private static final int MODE_SHIFT = 30;      

         public static final int EXACTLY     = 1 << MODE_SHIFT;    //填满父控件高度
public static final int AT_MOST = 2 << MODE_SHIFT; //自适应当前控件高度

可以看到,分别是将1和2向左移了30位,为什么向左移30位呢?

android中把测量出的int做了处理,int类型的长度是32位,把前两位作为标记位,标记了测量模式,如EXACTLY、AT_MOST,把最后30位作为测量的具体高度或者是宽度。

也就是说把一个int分为了两部分,是一个int同时具有了测量模式和具体数值两部分信息!

EXACTLY的值是1向左进位30,就是01 00000000000…(01后跟30个0) 
AT_MOST的值是2向左进位30,就是10 00000000000…(10后跟30个0) 

所以我们在调用MeasureSpec.makeMeasureSpec(size,mode)方法时,传入的size参数要把Integer.MAX_VALUE右移2位,因为前两位会被认为是标志,而不是值。这样我们传入的参数才会被认为是最大的int类型的值,同时传入AT_MOST作为模式,那么前两位就会被赋值为10,那么我们来实际计算一下,我们调用MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST)的实际结果是多少:

int类型长度是32位,其中包含1个标准位,所有最大值Integer.MAX_VALUE为 2的31次方 :2147483648
16进制下为0x7fffffff,二进制为:01 11111111111…(01后跟30个1)
由于前两位在android测量基础下是无效的标志位,所以我们右移2位的结果为000111111111111…
调用makeMeasureSpec方法后会把前两位替换为AT_MOST的前两位(其实是直接相加)
结果为:100111111111… 十六进制:9fffffff,十进制:-1610612737 所以你调试的时候后发现,返回的值为-1610612737 ,就是这个原因,因为前2位是无效的标志位,所以其实这个数所代表的最大值是 2的29次方:536870912。所以对于android测量机制来理解我们传入的-1610612737,是这样理解的:
 -1610612737  代表: 测量模式为AT_MOST,最大高度为536870912(2的29次方)

 关于MeasureSpec类的使用可以移文这篇博客:

android学习——MeasureSpec介绍及使用

ScrollView嵌套使用ListView冲突的解决与分析的更多相关文章

  1. (转)ViewPager,ScrollView 嵌套ViewPager滑动冲突解决

    ViewPager,ScrollView 嵌套ViewPager滑动冲突解决 本篇主要讲解一下几个问题 粗略地介绍一下View的事件分发机制 解决事件滑动冲突的思路及方法 ScrollView 里面嵌 ...

  2. PullToRefreshListView中嵌套ViewPager滑动冲突的解决

    PullToRefreshListView中嵌套ViewPager滑动冲突的解决 最近恰好遇到PullToRefreshListView中需要嵌套ViewPager的情况,ViewPager 作为头部 ...

  3. 解决 listView gridView 与ScrollView嵌套时的冲突

    package com.xqx.fight; import android.app.Activity; import android.os.Bundle; import android.view.Me ...

  4. Android Scrollview嵌套下listView动态加载数据,解决onScrollChanged执行多次数据重复问题

    这一篇博客和上一篇讲的都是listView的动态加载,但有所不同的是,本篇的listView是嵌套在ScrollView下的,有时候在一个Activity中可能分为好几个模块,由于展示的需要(手机屏幕 ...

  5. 解决ScrollView嵌到listView冲突问题

    方法一: 把下面的方法放在绑定适配器操作的下面就行. /** * 重新计算ListView的高度,解决ScrollView和ListView两个View都有滚动的效果,在嵌套使用时起冲突的问题 * @ ...

  6. 重写ScrollView 解决ScrollView嵌套viewpager事件冲突

    import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetecto ...

  7. Android scrollview嵌套webview滑动冲突的解决方案

    在Android开发中有时我们需要在scrollview中嵌套webview这时你会发现这两者的滑动事件产生了冲突导致:webview很难被滑动,即使被滑动了一点也非常不顺畅.解决方案也比较简单只需要 ...

  8. ScrollView嵌套Linearlayout显示不全的解决办法

    以为ScrollView只能嵌套一个元素,所以把几个控件都包裹在了一个LinearLayout中了.但是发现底部显示不全,滑动不到最底下. 代码: <ScrollView android:id= ...

  9. Android中scrollview嵌套HorizontalScrollView卡顿现象解决

    开发中经验会遇到滑动里面嵌入滑动的问题,但是这种情况下触摸事件就会发生冲突.导致滑动非常卡,甚至出现程序停止响应.这种情况下我们一般需要重写view.下面给出重新scrollview的方法 publi ...

随机推荐

  1. AppBox升级进行时 - 关联表查询与更新(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 关联表的查询操作 使用 Include 方法,我们可以在一次数据库查询中将关联 ...

  2. grunt配置太复杂?使用Qbuild进行文件合并、压缩、格式化等处理

    上次简单介绍了下Qbuild的特点和配置,其实实现一个自动化工具并不复杂,往简单里说,无非就是筛选文件和处理文件.但Qbuild的源码也并不少,还是做了不少工作的. 1. 引入了插件机制.在Qbuil ...

  3. ural 1072&period; Routing

    1072. Routing Time limit: 1.0 secondMemory limit: 64 MB There is a TCP/IP net of several computers. ...

  4. 记一次linux服务器问题处理过程

    本周二的时候,涛哥找我,说明了一件事,在安装ganglia的时候,发生的一个问题. 在一台suse 10 sp1的服务器上,安装ganglia的一个依赖包,libconfuse.rpm,安装完成之后, ...

  5. 扫描函数sweep

    groot.sweep(element,vm); element 为要扫描的代码片段,vm 对应的一个 groot.view 定义的 一个Vm的整体 扫面代码 groot.sweep = functi ...

  6. ACM心情总结

    已经快要12点了,然而还有5000字概率论论文没有动.在论文里,我本来是想要总结一下ACM竞赛中出现过的概率论题目,然而当敲打第一段前言的时候,我就迟疑了. 我问自己,ACM竞赛到底有什么现实意义. ...

  7. 网易云课堂&lowbar;C&plus;&plus;程序设计入门&lpar;上&rpar;&lowbar;第2单元:丹青画松石– EGE图形库

    第2节:一个简单的EGE程序 #ifndef _GRAPHICS_H_ #define _GRAPHICS_H_ #ifndef __cplusplus #error You must use C++ ...

  8. Python爬虫:通过关键字爬取百度图片

    使用工具:Python2.7 点我下载 scrapy框架 sublime text3 一.搭建python(Windows版本) 1.安装python2.7 ---然后在cmd当中输入python,界 ...

  9. 送你一双看见时间的眼睛--时间master软件

    开篇语 最近感觉自己时间管理非常错乱,所以去网上找了一些有关于时间管理的软件.然后发现了好几款还不错的软件或者是微信上的应用,下面我把我的一些使用情况以及如何使用的方法写出来,给有需要的朋友进行借鉴! ...

  10. &lbrack;转帖&rsqb;Zoom

    Zoom美国上市:华裔创始人为大股东 创业想法来自“异地恋” https://baijiahao.baidu.com/s?id=1631166070308020680&wfr=spider&a ...