ScrollView与Listview滑动冲突解决-程序员宅基地

技术标签: android  listview  

在实际应用中,经常会碰到非常规的布局要求,比如说在ScrollView里嵌套ListView,ScrollView和ListView都是可以滚动的控件,这样布局看似很奇怪,但是有些效果又不得不这样做。比如说:一个长布局中有部分是列表格式,布局长度又超过屏幕高度,这样的情况就得使用这种布局了。

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentLeft="true"
    android:fillViewport="true">

    <LinearLayout
        android:id="@+id/showin"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"/>

    </LinearLayout>
</ScrollView>

但是实际试过之后就会发现这样做有一个问题,无论ListView的高度怎么设置,都会只显示一行的高度,那是由于ListView的父容器测量模式为UNSPECIFIED的时候,ListView的高度默认为一个item的高度,ListView中源码如下:

if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight +
getVerticalFadingEdgeLength() * 2;
}
这样我们就重写ListView的onMeasure方法,来自定义高度:

/**
 * 重写该方法,达到使ListView适应ScrollView的效果
 */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
    super.onMeasure(widthMeasureSpec, expandSpec);
}

像如上这样重写onMeasure方法,就能让ScrollView嵌套中的ListView完全填满。仔细看,会发现上面的代码很奇怪,下面解释下其原理,不想了解的可以跳过了。

原理分析:

查看上面的代码我们发现我们把高度写成了一个固定值expandSpec ,这个值是这样计算出来的

expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
从上面代码可以看出,把整数类型的最大值右移了2位,作为size传入,另外把一个AT_MOST的常量作为mode传入。

为什么要传入这样一个奇葩的参数呢,这就Android的实体测量机制有关了,android中规定,测量的值(高度或宽度)为一个int类型,但不是普通的int,而是一个进过处理的int,在view视图中我们制定一个高度需要2个参数,1个是具体的值,一个是测量模式,测量模式就是我们在布局中经常用到的MATCH_PARENT 、WRAP_CONTENT。他们是一个int型的常量,对应的值分别是:

LayoutParams.MATCH_PARENT 对应 MeasureSpec.EXACTLY
LayoutParams.WRAP_CONTENT 对应 MeasureSpec.AT_MOST
而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位的值。为什么会这样呢?

android中把测量出的int做了处理,int的长度时32位,把前2位作为标志位标示了测量模式,如EXACTLY、AT_MOST
把后30位作为测量的具体高度或宽度。
也就是说,把一个int分成了2部分,使一个int值同时拥有了模式和具体数值的2部分信息!

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次方)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_23901559/article/details/51883582

智能推荐

Dot NET设计模式—反射工厂 -程序员宅基地

1.概述 如果采用传统方式实现了简单工厂、工厂方法和抽象工厂在有些场合下如此处理,代码会变得冗余并且难以维护。 假设我们需要创建一种交通工具,可以是汽车、火车或者轮船,结构如图所示。 我们可以采用简单工厂,通过参数指示创建所需要的对象类型。如果增加子类,例如卡车和轿车等,则必须增加参数的相应的代码。如果子类层

2021年资料员-通用基础(资料员)考试及资料员-通用基础(资料员)免费试题_2023年【资料员-通用基础(资料员)】报名考试及资料员-通用基础(资料员)免费试题-程序员宅基地

题库来源:安全生产模拟考试一点通公众号小程序资料员-通用基础(资料员)考试参考答案及资料员-通用基础(资料员)考试试题解析由安全生产模拟考试一点通题库老师及资料员-通用基础(资料员)操作证已考过的学员汇总,相对有效帮助资料员-通用基础(资料员)免费试题学员顺利通过考试。1、【判断题】施工项目是指建筑企业自施工投标开始到保修期满为止的全部过程中完成的项目。(√)2、【判断题】市政工程费用计价方法与建筑工程计价方法是相同的。(√)3、【判断题】工会经费是指企业按职工工资总额计..._2023年【资料员-通用基础(资料员)】报名考试及资料员-通用基础(资料员)免费试题

appcompat_v7的问题-程序员宅基地

新用的android开发项目,不知怎么出了appcompat_v7这个不速之客,图痛快,挥键一删。完了,报七七八八莫名的错误,新建工程也报错,拷贝一个appcompat_v7到指定的文件夹,也不行。花了一天也没搞好。后来重新建新的workspace,一切都好了。记住,想不出法子时就去睡觉,千万不要加班,没用。

基于matlab/simulink的电力电子三相整流(可直接出仿真结果图)_simulink 整流器-程序员宅基地

在三相桥式全控整流电路中,对共阴极组和共阳极组是同时进行控制的,控制角都是α。由于三相桥式整流电路是两组三相半波电路的串联,因此整流电压为三相半波时的两倍。很显然在输出电压相同的情况下,三相桥式晶闸管要求的最大反向电压,可比三相半波线路中的晶闸管低一半。_simulink 整流器

k8s 用PV & PVC 的创建persistent Volume_创建persistentvolume-程序员宅基地

今天实践了在k8s server 上安装PV, PVC 安装nfs 的文件系统。PersistentVolume (PV) 是外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim)。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储..._创建persistentvolume

Javascript中addEventListener和attachEvent的区别-程序员宅基地

在利用javascript为DOM Element添加事件处理程序时,如果要想下兼容IE6,7时,就不得不考虑addEventListener与attachEvent的异同。 1.首先说下addEventListener,现在IE9+,chrome,firefox等都支持。 所有的DOM节点包含addEventListener,并且接受3个参数: HTMLElement.addEventLi...

随便推点

初学java2E-程序员宅基地

UML统一建模语言类框图圆形时序图组件图部署图Collection接口1.1 集合框架的顶级接口1.2 是Set和List的父接口1.3 但不是Map的父接口List接口2.1 特点:有序、对象可以重复2.2 遍历方式2.2.1 下标2.2.2 foreach(>=jdk1.5)2.2.3 迭代器Iterator2.3 List优化初始容量10..._java2e

mathematica中同时判断多个函数——可变动参数的情况-程序员宅基地

利用Manipulate和Animate函数代码示例:Clear["`*"];Manipulate[{Reduce[ Maximize[{a*x^2 - b, 0 <= x <= 1}, {x}][[2, 1, 2]] > 0], Reduce[Maximize[{a*x^2 - b, 0 <= x <= 1}, {x}][[2, 1, 2]] == 0], Reduce[Maximize[{a*x^2 - b, 0 <= x <= 1

《第一行代码》第二版 学习总结5 四大布局简介-程序员宅基地

最近利用下班时间,找了看什么书比较适合初学android的朋友,很多人推荐了这本书,于是就买了一本,感觉看书,思考,动手,再思考和总结这样过程还是很有必要的,于是就打算把自己学习的东西简单的总结一下;方便自己以后查找,也有利于学习的巩固。在这里首先要感谢一下书籍的作者——郭霖前辈。 布局对于每一个应用来说都是不可或缺并且是至关重要的;本来应该早一点介绍一下;但是我把V...

几个不太常用的HTML Tag-程序员宅基地

几个不太常用的HTML Tag ,看看大家有没有用得着的地方;转载自CSDN:1. LabelLabel是用来标记Input元素的提示的。Label的“For”属性要和Input元素的ID相一致。好处:点击提示文字,就自动Focus对应的输入元素。对于Radio,Checkbox这类点击区域特别小的控件特别有用:Color: red green blue 2. Fie_html tag

加深对HTML和CSS标签语义化的理解-程序员宅基地

首先说明的一点是,人可以通过视觉的划分判断内容的语义,搜索引擎看到的只是代码。搜索引擎只能通过标签来判断内容的语义。 以前我真的没有怎么重视过搜索引擎,现在开始比较在意了,因为页面的很大一部分流量是来自搜索引擎的,要使页面尽可能地对搜索引擎友好,所以就要尽可能地使标签语义化。以前以我对web开发的粗浅理解,觉得写一个好的符合标准的页面只需要把结构和表现分离,然后不要使用table,font等标...

期货从入门到高深之量化交易1_期货量化交易tb_大邦村民的博客-程序员宅基地

期货从入门到高深之量化交易1-------- 初识量化交易 下集讲软件运用_期货量化交易tb