Android自定义控件系列一:如何测量控件尺寸

测量控件尺寸(宽度、高度)是开发自定义控件的第一步,只有确定尺寸后才能开始画(利用canvas在画布上画,我们所使用的控件实际上都是这样画上去的)。当然,这个尺寸是需要根据控件的各个部分计算出来的,比如:padding、文字大小,间距等。

非容器控件的onMeasure

下面我们就来看看如何给非容器控件(即直接extends View)这只尺寸的:

1.@Override

2.protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

3.setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));

4.}

通过重写onMeasure()方法来设置尺寸。这个方法实际是由容器控件(LinearLayout、RelativeLayout)来调用的,以便容器控件知道我需要分配给你多大空间或尺寸。

计算完尺寸后,最终调用setMeasuredDimension()来设置。比如,我要创建个 宽度是200px,高度是100px的控件,就可以setMeasuredDimension(200, 100)。

注意setMeasuredDimension()接收的值是px值,而不是dp值,所以我们不可能像上面那样将尺寸写固定的。如何做那:

参数 int widthMeasureSpec, int heightMeasureSpec 是指明控件可获得的空间以及关于这个空间描述的元数据,是与布局文件中android:layout_width、android:layout_height相联系的。如何使用:

01.   /**

02.* 计算组件宽度

03.*/

04.private int measureWidth(int widthMeasureSpec) {

05.int result;

06.int specMode = MeasureSpec.getMode(widthMeasureSpec);

07.int specSize = MeasureSpec.getSize(widthMeasureSpec);

08.

09.if (specMode == MeasureSpec.EXACTLY) {//精确模式

10.result = specSize;

11.else {

12.result = getDefaultWidth();//最大尺寸模式,getDefaultWidth方法需要我们根据控件实际需要自己实现

13.if (specMode == MeasureSpec.AT_MOST) {

14.result = Math.min(result, specSize);

15.}

16.}

17.return result;

18.}

调用MeasureSpec.getMode(measureSpec),可以获得设置尺寸的mode(模式)。

mode共有三种情况,取值分别为:

MeasureSpec.UNSPECIFIED,MeasureSpec.EXACTLY,MeasureSpec.AT_MOST。

MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。

MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。

MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。

measureWidth() 方法是个固定实现,几乎不用改, 唯一需要我们实现的就是getDefaultWidth()。即,当mode处于最大模式下,此时父容器会将他所能给你的或者说目前剩余的最大空间给你。你只能在这个空间内设定控件尺寸。一个简单的类似TextView的getDefaultWidth()的实现:

1.private void getDefaultWidth(){

2.int txtWidth = (int)this.paint.measureText(this.text);

3.return txtWidth + this.paddingLeft + this.paddingRight;

4.}

上面说了宽度的测量,高度同理:

01.   /**

02.* 计算组件高度

03.*/

04.private int measureHeight(int measureSpec) {

05.int result;

06.int specMode = MeasureSpec.getMode(measureSpec);

07.int specSize = MeasureSpec.getSize(measureSpec);

08.

09.if (specMode == MeasureSpec.EXACTLY) {

10.result = specSize;

11.else {

12.result = getDefaultHeight();

13.if (specMode == MeasureSpec.AT_MOST) {

14.result = Math.min(result, specSize);

15.}

16.}

17.return result;

18.}

有了上面的实现,我们就可以在布局文件中使用控件时,通过android:layout_width、android:layout_height来自定义控件的宽度、高度。

容器控件的onMeasure

容器控件一般是继承ViewGroup,ViewGroup是个抽象类,本身没有实现onMeasure,但是他的子类都有各自的实现,通常他们都是通过measureChildWithMargins函数或者其他类似于measureChild的函数来遍历测量子View,被GONE的子View将不参与测量,当所有的子View都测量完毕后,才根据父View传递过来的模式和大小来最终决定自身的大小.

在测量子View时,会先获取子View的LayoutParams,从中取出宽高,如果是大于0,将会以精确的模式加上其值组合成MeasureSpec传递子View,如果是小于0,将会把自身的大小或者剩余的大小传递给子View,其模式判定在前面表中有对应关系.

ViewGroup一般都在测量完所有子View后才会调用setMeasuredDimension()设置自身大小。

==========================================================================================

欢迎加入我们的技术交流群:
Android群: 66756039
JavaEE群:  361579846

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-29 23:29:37

Android自定义控件系列一:如何测量控件尺寸的相关文章

Android自定义控件之轮播图控件

背景 最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码.于是自己封装了一下.本篇轮播图实现原理原文出处:循环广告位组件的实现,这里只是做了下封装成一个控件,不必每次重复写代码了. 效果图 实现分析 轮播图的功能就是实现左右滑动的广告.图片信息展示,那我们就用ViewPager来实现,由于考虑到用户体验,我们还需要在下面加一个指示器来标示滑动到了第几张轮播图.指示器我们可以用一个线性布局来根据要展示的轮

android自定义控件之飞入飞出控件

最近呢,本人辞职了,在找工作期间,不幸碰到了这个求职淡季,另外还是大学生毕业求职的高峰期,简历发了无数份却都石沉大海,宝宝心里那是一个苦啊!翻着过去的代码,本人偶然找到了一个有意思的控件,那时本人还没有写博客的习惯,现在补上,先看效果图: 然后看用法代码: StellarMap stellarMap = (StellarMap) findViewById(R.id.stellar); // 设置数据 RecommendAdapter adapter = new RecommendAdapter(

Android自定义控件(一)——开关控件

Google 在 API 14 开始才新增了Switch 控件. 因此,我们可以选择自己封装一个Switch . 效果如图: View主要代码: [java] view plaincopy public class SwitchView extends LinearLayout { private ImageView maskImage;              // 开关遮盖图片 private boolean open;                     // 开关当前状态 priv

Android自定义控件系列二:如何自定义属性

上一篇Android自定义控件系列一:如何测量控件尺寸 我们讲了如何确定控件的属性,这篇接着也是讲个必要的知识-如何自定义属性.对于一个完整的或者说真正有实用价值的控件,自定义属性是必不可少的. 如何为控件定义属性 在res/values/attrs.xml(attrs.xml如果不存在,可以创建个)中使用<declare-styleable>标签定义属性,比如我想定义个显示头像的圆形的图片控件(AvatarImageView): 01.<?xml version="1.0&q

Android自定义控件系列七:详解onMeasure()方法中如何测量一个控件尺寸(一)

转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45027641 自定义view/viewgroup要重写的几个方法:onMeasure(),onLayout(),onDraw().(不熟悉的话可以查看专栏的前几篇文章:Android自定义控件系列二:自定义开关按钮(一)). 今天的任务就是详细研究一下protected void onMeasure(int widthMeasureSpec, int heightMeasureSpe

Android自定义控件系列 十:利用添加自定义布局来搞定触摸事件的分发,解决组合界面中特定控件响应特定方向的事件

这个例子是比较有用的,基本上可以说,写完这一次,以后很多情况下,直接拿过来addView一下,然后再addInterceptorView一下,就可以轻轻松松的达到组合界面中特定控件来响应特定方向的触摸事件了. 请尊重原创劳动成果,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45198549,非允许请勿用于商业或盈利用途,违者必究. 在写Android应用的过程之中,经常会遇到这样的情况:界面包含了多个控件,我们希望触摸在界面上的不

android自定义控件系列教程----视图的测量和布局

前面说点什么 当我们的一个视图界面绘制在android屏幕上面的时候其实都必须经过这几步measure. layout.draw这几个阶段,我们可以在view类里面看到这几个函数,然后里面有几个函数是onmeasure.onlayout.ondraw这几个函数是我们重写控件需要注意的这几个函数,下面我们就来讲讲这几个函数的功能和作用. onMeasure 正如这个函数的名子一样就是测量,所有的图示其实系统在绘制之前都不知道它到底有多大的,所以在很多时候我们在初始化界面oncreate的时候直接去

Android自定义控件系列八:详解onMeasure()(二)--利用onMeasure测量来实现图片拉伸永不变形,解决屏幕适配问题

上一篇文章详细讲解了一下onMeasure/measure方法在Android自定义控件时的原理和作用,参看博文:Android自定义控件系列七:详解onMeasure()方法中如何测量一个控件尺寸(一),今天就来真正实践一下,让这两个方法大显神威来帮我们搞定图片的屏幕适配问题. 请尊重原创劳动成果,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45038329,非允许请勿用于商业或盈利用途,违者必究. 使用ImageView会遇到

[转]Android自定义控件系列五:自定义绚丽水波纹效果

出处:http://www.2cto.com/kf/201411/353169.html 今天我们来利用Android自定义控件实现一个比较有趣的效果:滑动水波纹.先来看看最终效果图: 图一 效果还是很炫的:饭要一口口吃,路要一步步走,这里我们将整个过程分成几步来实现 一.实现单击出现水波纹单圈效果: 图二 照例来说,还是一个自定义控件,这里我们直接让这个控件撑满整个屏幕(对自定义控件不熟悉的可以参看我之前的一篇文章:Android自定义控件系列二:自定义开关按钮(一)).观察这个效果,发现应该