尺寸测量的配置

控件宽和高的设置方式

大家知道,自定义视图的目的就是要在屏幕上显示期望的图案,那在绘制图案之前,我们得先知道这个图案的尺寸(如宽多少高多少)。
一般在xml中给控件的宽和高有三种赋值方式:
1、MATCH_PARENT : 表示与上级控件一样大小;
2、WRAP_CONTENT : 表示按照自身尺寸进行适配;
3、直接赋给具体的dp值;
方式3有具体的数值,不用计算就知道了。方式1与上级控件保持一致,因此只要系统依次丈量控件大小,这也不是什么难事。麻烦的是方式2,因为下级控件每个尺寸都有可能不确定,比如文本控件得看文字大小、行数,图像控件得看图片大小、拉伸情况,所以大家想想,如果这时候我们自己去一个个算过去(下级控件的个数也不确定),这算得头都大了。
幸亏Android提供了onMeasure函数自动完成了上述计算过程,通常情况下我们的自定义控件也无需重写该方法,除了一些特殊的情况。当然本文讲的便是实际开发中遇到的特殊情况,否则就不用浪费口舌了。

尺寸测量配置的三种模式

对应上面layout_width和layout_height的三种赋值方式,Android的视图底层也提供了三种测量模式,分别是:
1、MeasureSpec.AT_MOST : 表示达到最大,该常量的十进制数值为-2147483648,对应赋值方式的MATCH_PARENT;
2、MeasureSpec.UNSPECIFIED : 表示未指定(实际就是自适应),该常量的十进制数值为0,对应赋值方式的WRAP_CONTENT;
3、MeasureSpec.EXACTLY : 表示精确,该常量的十进制数值为1073741824,对应赋值方式的具体dp值;
围绕着这三种模式,衍生了MeasureSpec的相关方法,如getChildMeasureSpec、makeMeasureSpec、measure等等。废话少说,让我们直接切入正题,看看测量模式怎么用,以及用在哪里。

下拉刷新框架中的尺寸测量

许多APP都有下拉刷新的功能,比如下面这个图片是一种下拉刷新的展示框:

平时页面打开是没有这个下拉框的,只有用户在屏幕上用手指向下滑动时,才会拉出这个下拉框,然后APP响应下拉事件进行刷新处理。这期间我们需要获得下拉区域的高度,以便把整个页面下移一段距离,从而展现下拉框区域。等到刷新操作结束,整个页面再往上挪回原位,同时收回下拉框。
现在问题就是,刷新时,整个页面要下移多少dp?其实这个下移的距离就是下拉区域的高度,所以只要我们在代码中算出下拉区域的高度,就能够移动合适的距离了。
在Android规定的测量过程中,主要有三个步骤:
1、获得宽与高的测量模式;
2、按照测量模式进行丈量;
3、获得测量后的宽与高的大小;

获得宽与高的测量模式

首先取到目标视图的宽和高的取值,从布局参数中获取:

ViewGroup.LayoutParams params = aViewObject.getLayoutParams();
int originWidth = params.width;
int originHeight = params.height;

获取到的原始尺寸大小,为-1时表示MATCH_PARENT,为-2时表示WRAP_CONTENT,其余值表示具体数值。
接着按照原始尺寸去匹配测量模式,这里我们获取宽度模式采用了getChildMeasureSpec方法,获取高度模式采用了makeMeasureSpec方法。getChildMeasureSpec的好处是可以设置边距,并且按常规处理无需我们再分支处理;makeMeasureSpec则更灵活,像下拉刷新会不断更新下拉区域的实际高度,偏移量可能是负数统统需要重新适配,如果按照常规处理,非-1也非-2的负数被当作精确值就不会重新适配了。

     int widthSpec = ViewGroup.getChildMeasureSpec(MeasureSpec.UNSPECIFIED, 0, params.width);int heightSpec;if (params.height <= 0) {heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);} else {heightSpec = MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY);}

按照测量模式进行丈量

实际丈量的方法很简单,直接使用上面计算得到的宽和高的模式,measure一下就可以了。当然要用一个视图的对象去操作measure

aViewObject.measure(widthSpec, heightSpec);

获得测量后的宽与高的大小

这个也简单,获取宽度用getMeasuredWidth,获取高度用getMeasuredHeight

int realWidth = aViewObject.getMeasuredWidth();
int realHeight = aViewObject.getMeasuredHeight();

下面是下拉刷新的效果图

PullToRefresh

说到下拉刷新,刚好介绍一下使用广泛的开源框架PullToRefresh,该框架支持ScrollView、ListView、GridView多种视图,也支持下拉刷新和上拉加载两种模式,可适用于多种场合。

PullToRefresh是个单独的工程,需做为库工程引入到开发者自己的工程。PullToRefresh对象常用的方法有:
setMode : 设置拉动模式。Mode.PULL_FROM_START表示从上往下拉(即下拉刷新),Mode.PULL_FROM_START表示从下往上拉(即上拉加载),Mode.BOTH表示既支持下拉刷新也支持上拉加载。
getLoadingLayoutProxy : 获取加载区域的对象。接着可调用该对象的如下方法:
--setPullLabel : 设置拉动时文本
--setReleaseLabel : 设置松开时的文本
--setRefreshingLabel : 设置刷新时的文本
--setLastUpdatedLabel : 设置无需更新时的文本
setOnRefreshListener : 设置刷新监听器。刷新监听器主要有OnRefreshListener和OnRefreshListener2两种,前者是普通刷新,需重写监听方法onRefresh;后者是双重刷新,需重写监听方法onPullDownToRefresh(下拉监听)、onPullUpToRefresh(上拉监听)。
getRefreshableView : 获取可刷新的视图对象,如ScrollView、ListView、GridView等等,接着方可调用视图对象的相应方法,如setAdapter等等。

下面是PullToRefresh的一个使用例子代码:

     PullToRefreshListView ptrl_hello = (PullToRefreshListView) findViewById(R.id.ptrl_hello);//从下往上拉,上拉加载//ptrl_hello.setMode(Mode.PULL_FROM_END);ptrl_hello.setMode(Mode.BOTH); //试试如何区分下拉与上拉两个监听器//设置下拉刷新的文字ptrl_hello.getLoadingLayoutProxy().setLastUpdatedLabel("当前已是最新数据");ptrl_hello.getLoadingLayoutProxy().setPullLabel("拉动标志");ptrl_hello.getLoadingLayoutProxy().setRefreshingLabel("数据更新中...");ptrl_hello.getLoadingLayoutProxy().setReleaseLabel("松开标志");//设置上拉加载的文字ptrl_hello.getLoadingLayoutProxy(false,true).setLastUpdatedLabel("当前已是最新数据");ptrl_hello.getLoadingLayoutProxy(false,true).setPullLabel("拉动标志");ptrl_hello.getLoadingLayoutProxy(false,true).setRefreshingLabel("数据更新中...");ptrl_hello.getLoadingLayoutProxy(false,true).setReleaseLabel("松开标志");ptrl_hello.setOnRefreshListener(new OnRefreshListener2<ListView>() {@Overridepublic void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) {Toast.makeText(FrameListActivity.this, "列表视图在处理下拉刷新数据啦", Toast.LENGTH_LONG).show();ptrl_hello.onRefreshComplete();}@Overridepublic void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) {Toast.makeText(FrameListActivity.this, "列表视图在处理上拉加载数据啦", Toast.LENGTH_LONG).show();ptrl_hello.onRefreshComplete();}});String[] starArray = {"水星", "金星", "地球", "火星", "木星", "土星"};ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.spinner_item, starArray);ptrl_hello.getRefreshableView().setAdapter(adapter);

点击下载本文用到的下拉刷新框架代码

点此查看Android开发笔记的完整目录

Android开发笔记(十二)测量尺寸与下拉刷新相关推荐

  1. Android开发笔记(二十四)res目录的结构与配置

    res目录结构 res是Android项目工程中存放各类的目录,主要包括布局.图形与配置等等.res的子目录主要有: anim : 存放动画的描述文件 drawable : 存放各类图形的描述文件,包 ...

  2. Android开发笔记(二十七)对象序列化

    什么是序列化 程序中存储和传递信息,需要有个合适的数据结构,最简单的是定义几个变量,变量多了之后再分门别类,便成了聚合若干变量的对象.代码在函数调用时可以直接传递对象,但更多的场合例如与文件交互.与网 ...

  3. Android开发笔记(二十二)瀑布流网格WaterfallGridView

    瀑布流网格的产生背景 Android中展示门类信息一般使用列表视图ListView或者网格视图GridView,特别是电商类APP的首页,除了顶部导航.底部标签.上方横幅外,主要页面都是展示各种商品和 ...

  4. Android开发笔记(二十九)使用SharedPreferences存取数据

    SharedPreferences使用场景 共享参数(SharedPreferences)是Android上的一个轻量级存储工具,存储结构是类似map的key-value键值对形式.它主要用于保存ap ...

  5. Android开发笔记(二十八)利用Application实现内存读写

    全局变量 C/C++有所谓的全局变量,因为全局变量保存在内存中,所以操作全局变量就是操作内存,其速度远比操作数据库或者操作文件快得多,而且工程里的任何代码都可以引用全局变量,因此很多时候全局变量是共享 ...

  6. Android开发笔记(二十六)Java的容器类

    容器的分类 集合(Set/HashSet) 集合中的元素是没有顺序的,而且不可以重复.这意味着,集合只能遍历而无法通过索引访问指定元素,并且如果重复添加相同值将不会增大集合.因为Set只是接口,所以实 ...

  7. Android开发笔记(二十五)assets目录下的文件读取

    AssetManager工具类 assets目录用于存放应用程序的资产文件,该目录下的文件不会被系统编译,所以无法通过R.*.*这种方式来访问.Android专门为assets目录提供了一个工具类As ...

  8. Android开发笔记(二十)顶部导航栏ActionBar

    标题栏ActionBar ActionBar是在Android3.0之后引入的,所以Android2.x之前的版本不能直接使用ActionBar.现在ActionBar广泛用做APP的顶部导航栏,它在 ...

  9. 【Visual C++】游戏开发笔记十二 游戏输入消息处理(一) 键盘消息处理

    相信大家都熟悉<仙剑奇侠传98柔情版>的人机交互方式,用的仅仅是键盘.在那个物质并不充裕的时代,一台配置并不高的电脑,一款名叫<仙剑奇侠传>的游戏,却能承载一代人对梦想的追逐. ...

最新文章

  1. 判断jQuery库是否被正确引入
  2. 如何编写无法维护的代码_如何写出让同事无法维护的代码?
  3. 重磅:专门《Vue2.0基础》设计的1套练习题
  4. 【BZOJ4205】卡牌配对 最大流
  5. fastxml 大于符号不转换_JQuery框架及Ajax技术练习
  6. JVM虚拟机-Class文件简介
  7. Python案例:四种方式编程求解一元二次方程
  8. Atitit Elasticsearch6之elasticsearch5.x 新特性 目录 1.1. 其实,elasticsearch5.x 和 elasticsearch2.x 并不区别很大。 1
  9. 中文乱码问题:JSP页面的显示问题,获取中文参数值问题
  10. Python深度学习入门学习路线(简单速成不掉头发)
  11. java数据类型int_java数据类型
  12. 2020-12-10 PMP 群内练习题 - 光环
  13. 在php页面出现乱码的原因,html网页乱码原因与解决方法
  14. HTML+CSS基础知识2
  15. 2021鹏业安装算量软件常见问题整理(四)
  16. Windows驱动程序之cat文件介绍
  17. FITC-LCA荧光素标记小扁豆凝集素(LCA)
  18. 微信朋友圈两大神秘江湖帮派:养生党、鸡汤党
  19. PageAdmin CMS Sql新建数据库和用户名教程
  20. Linux操作系统中man命令的用法,Linux 系统中的MAN命令使用祥解

热门文章

  1. Algorithm:贪心策略之区间调度问题
  2. python判断字符串,str函数isdigit、isdecimal、isnumeric的区别
  3. java处理json的工具类(list,map和json的之间的转换)
  4. python接口自动化(十五)--参数关联接口(详解)
  5. java连接数据库 oracle,Oracle数据库之一分钟教你学会用java连接Oracle数据库
  6. 上deepweb难吗_发动机保养难?傲群除尘毛刷用上了吗
  7. [设计模式-结构型]享元模式(Flyweight )
  8. oracle内置函数 trunc 使用
  9. abap中读取excel中不同的sheet数据_Python 如何将数据写入Excel的不同或同一个工作簿中...
  10. http 直接显示目录下文件_Win10支持直接访问Linux子系统文件:你的下一台Linux何必是Linux