ScrollView嵌套ListView,ListView完全展开及makeMeasureSpec测量机制原理分析
在实际应用中,经常会碰到非常规的布局要求,比如说在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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
但是实际试过之后就会发现这样做有一个问题,无论ListView的高度怎么设置,都会只显示一行的高度,那是由于ListView的父容器测量模式为UNSPECIFIED的时候,ListView的高度默认为一个item的高度,ListView中源码如下:
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight +
getVerticalFadingEdgeLength() * 2;
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
这样我们就重写ListView的onMeasure方法,来自定义高度:
/**
* 重写该方法,达到使ListView适应ScrollView的效果
*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
像如上这样重写onMeasure方法,就能让ScrollView嵌套中的ListView完全填满。仔细看,会发现上面的代码很奇怪,下面解释下其原理,不想了解的可以跳过了。
原理分析:
查看上面的代码我们发现我们把高度写成了一个固定值expandSpec ,这个值是这样计算出来的
expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
- 1
- 1
从上面代码可以看出,把整数类型的最大值右移了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
- 1
- 2
- 1
- 2
而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
- 3
- 4
- 1
- 2
- 3
- 4
可以看到,分别是把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次方)
ScrollView嵌套ListView,ListView完全展开及makeMeasureSpec测量机制原理分析的更多相关文章
- ScrollView嵌套使用ListView冲突的解决与分析
因为ScrollView与ListView都是具有滚动条的控件,所以嵌套在一起使用的时候可能会出现事件的冲突,比如我就遇见了ListView中只显示一条数据的问题.解决的办法,就是自定义了一个List ...
- Android Scrollview嵌套下listView动态加载数据,解决onScrollChanged执行多次数据重复问题
这一篇博客和上一篇讲的都是listView的动态加载,但有所不同的是,本篇的listView是嵌套在ScrollView下的,有时候在一个Activity中可能分为好几个模块,由于展示的需要(手机屏幕 ...
- ScrollView嵌套ListView,GridView数据加载不全问题的解决
我们大家都知道ListView,GridView加载数据项,如果数据项过多时,就会显示滚动条.ScrollView组件里面只能包含一个组件,当ScrollView里面嵌套listView,GridVi ...
- 关于ScrollView嵌套ListView问题
Android开发之ScrollView中嵌套ListView的解决方案 原文:http://blog.csdn.net/minimicall/article/details/40983331 ...
- Android之ScrollView嵌套ListView和GridView冲突
由于ListView,GridView本身都继承于ScrollView,一旦在ScrollView中嵌套ScrollView, 在ScrollView中嵌套使用ListView或者GridView,L ...
- 四种方案解决ScrollView嵌套ListView问题(转)
以下文章转自@安卓泡面 在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全.我试过很多种方法,它们各有利弊. 在这里我将会从使用ScrollVie ...
- Android之ScrollView嵌套ListView冲突
在ScrollView中嵌套使用ListView,ListView只会显示一行多一点.两者进行嵌套,即会发生冲突.由于ListView本身都继承于ScrollView,一旦在ScrollView中嵌套 ...
- 冲突--ScrollView嵌套ListView冲突问题的最优解决方案
项目做多了之后,会发现其实 ScrollView嵌套ListVew或者GridView等很常用,但是你也会发现各种奇怪问题产生.根据个人经验现在列出常见问题以及代码最少最简单的解决方法. 问题一 : ...
- android 解决ScrollView嵌套ListView的问题,不能全屏,全屏不能显示下面控件
在开发中遇到ScrollView嵌套ListView的问题,最开始发出不能全屏,效果是这样的: 但我想要的效果是这样的: 下面看一下布局文件: <?xml version="1.0&q ...
随机推荐
- poj 2429 GCD & LCM Inverse 【java】+【数学】
GCD & LCM Inverse Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9928 Accepted: ...
- C++ 实践总结
对于一个应用程序而言,静态链接库可能被载入多次,而动态链接库仅仅会被载入一次. Gameloft面试之错误一 Event: 面试官说例如以下程序是能够链接通过的. class Base { Pu ...
- canvas使用1
画直线: ? 1 2 3 4 5 6 7 8 9 10 11 var c = document.getElementById("myCanvas"); //不要忘写document ...
- Lombok使用详解(转)
本文转自https://blog.csdn.net/u010695794/article/details/70441432 2017年04月22日 15:17:00 阅读数:10394 Lombok使 ...
- 猫都能学会的Unity3D Shader入门指南(二)
关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己也是Shader初学者,因此可能会存在错误或者疏漏,如果 ...
- 闪电侠第四季/全集The Flash迅雷下载
闪电侠第四季>(The Flash Season 4)是DC娱乐和华纳联手CW电视台制作的真人超级英雄系列剧,是美剧<闪电侠>系列的第四季. 该季于2017年10月10日在美国CW电 ...
- VS2010Web默认的浏览器设置和VS里调试JavaScript代码的设置
前言 重装系统后,VS调用的Web浏览器不是IE了,VS调式不了JavaScript代码了.这两天一直在试终于搞定了.这里查找的问题当然主要是VS里面调式JavaScript代码了. 第一种方式设置V ...
- 教你摆脱低级程序猿 项目中cocopads的安装使用
小农今天聊聊一款作为iOS开发者必备的第三方管理软件.希望程序猿朋友们看到小农的这篇文章后.可以真正的学会怎样灵活管理你项目中的第三方. (一)CocoaPods是什么? 首先我们来认识一下这款第三方 ...
- Benchmark简介
一.Benchmark简介Benchmark是一个评价方式,在整个计算机领域有着长期的应用.正如维基百科上的解释“As computer architecture advanced, it becam ...
- Django静态文件的加载以及STATIC_URL、 STATIC_ROOT 、STATICFILES_DIRS的区别
Djangon生产环境静态资源的处理 Django 关闭DEBUG模式后,就相当于是生产环境了. Django框架一旦作为生产环境,它的静态文件访问接口就不应该从Django框架中走,必须在Djang ...