在继承ViewGroup类时,需要重写两个方法,分别是onMeasure和onLayout。



1,在方法onMeasure中调用setMeasuredDimension方法



void android.view.View.setMeasuredDimension(int measuredWidth, int measuredHeight)



在onMeasure(int, int)中,必须调用setMeasuredDimension(int width, int height)来存储测量得到的宽度和高度值,如果没有这么去做会触发异常IllegalStateException。



2,在方法onMeasure中调用孩子的measure方法



void android.view.View.measure(int widthMeasureSpec, int heightMeasureSpec)



这个方法用来测量出view的大小。父view使用width参数和height参数来提供constraint信息。实际上,view的测量工作在onMeasure(int, int)方法中完成。因此,只有onMeasure(int, int)方法可以且必须被重写。参数widthMeasureSpec提供view的水平空间的规格说明,参数heightMeasureSpec提供view的垂直空间的规格说明。



3,解析onMeasure(int, int)方法



void android.view.View.onMeasure(int widthMeasureSpec, int heightMeasureSpec)



测量view及其内容来确定view的宽度和高度。这个方法在measure(int, int)中被调用,必须被重写来精确和有效的测量view的内容。



在重写这个方法时,必须调用setMeasuredDimension(int, int)来存储测量得到的宽度和高度值。执行失败会触发一个IllegalStateException异常。调用父view的onMeasure(int, int)是合法有效的用法。



view的基本测量数据默认取其背景尺寸,除非允许更大的尺寸。子view必须重写onMeasure(int, int)来提供其内容更加准确的测量数值。如果被重写,子类确保测量的height和width至少是view的最小高度和宽度(通过getSuggestedMinimumHeight()和getSuggestedMinimumWidth()获取)。



4,解析onLayout(boolean, int, int, int, int)方法



void android.view.ViewGroup.onLayout(boolean changed, int l, int t, int r, int b)



调用场景:在view给其孩子设置尺寸和位置时被调用。子view,包括孩子在内,必须重写onLayout(boolean, int, int, int, int)方法,并且调用各自的layout(int, int, int, int)方法。



参数说明:参数changed表示view有新的尺寸或位置;参数l表示相对于父view的Left位置;参数t表示相对于父view的Top位置;参数r表示相对于父view的Right位置;参数b表示相对于父view的Bottom位置。.



5,解析View.MeasureSpec类



android.view.View.MeasureSpec



MeasureSpec对象,封装了layout规格说明,并且从父view传递给子view。每个MeasureSpec对象代表了width或height的规格。



MeasureSpec对象包含一个size和一个mode,其中mode可以取以下三个数值之一:



    UNSPECIFIED,1073741824 [0x40000000],未加规定的,表示没有给子view添加任何规定。

    EXACTLY,0 [0x0],精确的,表示父view为子view确定精确的尺寸。

AT_MOST,-2147483648 [0x80000000],子view可以在指定的尺寸内尽量大。

在这里给大家举一个例子demo:

第一步:自定义一个View实现ViewGroup接口,即自定义ViewGroup:

  1. package net.loonggg.viewgroup;
  2.  
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7.  
  8. public class MyViewGroup extends ViewGroup {
  9.  
  10. public MyViewGroup(Context context) {
  11. super(context);
  12. }
  13.  
  14. public MyViewGroup(Context context, AttributeSet attrs) {
  15. super(context, attrs);
  16. }
  17.  
  18. public MyViewGroup(Context context, AttributeSet attrs, int defStyle) {
  19. super(context, attrs, defStyle);
  20. }
  21.  
  22. /**
  23. * 计算控件的大小
  24. */
  25. @Override
  26. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  27. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  28. int measureWidth = measureWidth(widthMeasureSpec);
  29. int measureHeight = measureHeight(heightMeasureSpec);
  30. // 计算自定义的ViewGroup中所有子控件的大小
  31. measureChildren(widthMeasureSpec, heightMeasureSpec);
  32. // 设置自定义的控件MyViewGroup的大小
  33. setMeasuredDimension(measureWidth, measureHeight);
  34. }
  35.  
  36. private int measureWidth(int pWidthMeasureSpec) {
  37. int result = 0;
  38. int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 得到模式
  39. int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 得到尺寸
  40.  
  41. switch (widthMode) {
  42. /**
  43. * mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY,
  44. * MeasureSpec.AT_MOST。
  45. *
  46. *
  47. * MeasureSpec.EXACTLY是精确尺寸,
  48. * 当我们将控件的layout_width或layout_height指定为具体数值时如andorid
  49. * :layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
  50. *
  51. *
  52. * MeasureSpec.AT_MOST是最大尺寸,
  53. * 当控件的layout_width或layout_height指定为WRAP_CONTENT时
  54. * ,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可
  55. * 。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
  56. *
  57. *
  58. * MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,
  59. * 通过measure方法传入的模式。
  60. */
  61. case MeasureSpec.AT_MOST:
  62. case MeasureSpec.EXACTLY:
  63. result = widthSize;
  64. break;
  65. }
  66. return result;
  67. }
  68.  
  69. private int measureHeight(int pHeightMeasureSpec) {
  70. int result = 0;
  71.  
  72. int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
  73. int heightSize = MeasureSpec.getSize(pHeightMeasureSpec);
  74.  
  75. switch (heightMode) {
  76. case MeasureSpec.AT_MOST:
  77. case MeasureSpec.EXACTLY:
  78. result = heightSize;
  79. break;
  80. }
  81. return result;
  82. }
  83.  
  84. /**
  85. * 覆写onLayout,其目的是为了指定视图的显示位置,方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下,
  86. * 才能确定怎么摆放
  87. */
  88. @Override
  89. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  90. // 记录总高度
  91. int mTotalHeight = 0;
  92. // 遍历所有子视图
  93. int childCount = getChildCount();
  94. for (int i = 0; i < childCount; i++) {
  95. View childView = getChildAt(i);
  96.  
  97. // 获取在onMeasure中计算的视图尺寸
  98. int measureHeight = childView.getMeasuredHeight();
  99. int measuredWidth = childView.getMeasuredWidth();
  100.  
  101. childView.layout(l, mTotalHeight, measuredWidth, mTotalHeight
  102. + measureHeight);
  103.  
  104. mTotalHeight += measureHeight;
  105.  
  106. }
  107. }
  108.  
  109. }

第二步,布局文件:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="#00f0f0"
  6. tools:context=".MainActivity" >
  7.  
  8. <net.loonggg.viewgroup.MyViewGroup
  9. android:id="@+id/myViewGroup"
  10. android:layout_width="480dp"
  11. android:layout_height="300dp"
  12. android:background="#0f0f0f" >
  13.  
  14. <TextView
  15. android:layout_width="200dp"
  16. android:layout_height="100dp"
  17. android:background="#000000"
  18. android:gravity="center"
  19. android:text="第一个TextView" />
  20.  
  21. <TextView
  22. android:layout_width="100dp"
  23. android:layout_height="200dp"
  24. android:background="#ffffff"
  25. android:gravity="center"
  26. android:text="第二个TextView" />
  27. </net.loonggg.viewgroup.MyViewGroup>
  28.  
  29. </RelativeLayout>

第三步,MainActivity.java:

  1. package net.loonggg.viewgroup;
  2.  
  3. import android.os.Bundle;
  4. import android.app.Activity;
  5.  
  6. public class MainActivity extends Activity {
  7.  
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. }
  13.  
  14. }

ok,你们大家懂了吗?有问题请留言。

通过重写ViewGroup学习onMeasure()和onLayout()方法的更多相关文章

  1. 继承ViewGroup学习onMeasure()和onLayout()方法

    在继承ViewGroup类时,需要重写两个方法,分别是onMeasure和onLayout. 1,在方法onMeasure中调用setMeasuredDimension方法void android.v ...

  2. 【转】ViewGroup的onMeasure和onLayout分析

    ViewGroup的onMeasure和onLayout分析 一个Viewgroup基本的继承类格式如下: 1 import android.content.Context; 2 import and ...

  3. Android的onMeasure和onLayout And MeasureSpec揭秘

    Android中自定义ViewGroup最重要的就是onMeasure和onLayout方法,都需要重写这两个方法,ViewGroup绘制 的过程是这样的:onMeasure → onLayout → ...

  4. 自定义控件详解(五):onMeasure()、onLayout()

    前言: 自定义控件的三大方法: 测量: onMeasure(): 测量自己的大小,为正式布局提供建议 布局: onLayout(): 使用layout()函数对所有子控件布局 绘制: onDraw() ...

  5. 自定义ViewGroup基础巩固1---理解onLayout()方法

    自定义ViewGroup这个是在android中自定义控件中不可获缺的很重要的一部分,关于它的意义这里就不过多阐述了,为了在未来深入上继续走下去,所以先把基础给打牢. 这篇主要是理解ViewGroup ...

  6. java===java基础学习(12)---方法的重写和重载

    覆盖 / 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为. 也 ...

  7. C#基础知识学习(1)方法的重写和隐藏

    做了1年多了C#,发现些项目过程中很多基础东西都不是很清晰,基础不够牢固.现在开始复习基础知识并做重点记录 方法需要被重写的时候,可以在方法前加入virtual使方法变成虚方法. 这样我们可以重新写个 ...

  8. Android开发之View重写相关API-onLayout,onMeasure,MeasureSpec

     1.onLayout android.view.ViewGroup protected void onLayout(boolean changed, int l, int t, int r, int ...

  9. 对于view的深入理解,续篇(一)重写ViewGroup的onDraw

    在上一篇文章中,不仅熟悉了动态设定布局的方法,而且也对view的绘制流程有所了解.于是我继续做了下面几个实验,发现了一个问题.如果对view的绘制流程不是很明白,可以看看我的上一篇文章的介绍,点击下面 ...

随机推荐

  1. April 28 2017 Week 17 Friday

    The only thing more painful than learning from experience is not learning from experience. 比从经验中学习更为 ...

  2. python 字符串部分总结

    字符串 对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符 >>> ord('A') 65 >>> ord ...

  3. IOS Git源代码管理工具

    .新建一个“本地仓库” $ git init .配置仓库 >告诉git你是谁 git config user.name lnj >告诉git怎么联系你 git config user.em ...

  4. hdu-2609 How many---最小表示法模板+set判重

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2609 题目大意: 有n个有01组成的字符串,每个字符串都代表一个项链,那么该字符串就是一个环状的结构 ...

  5. [Linux发行版] 常见Linux系统下载(转)

    本专题页汇总最受欢迎的Linux发行版基本介绍和下载地址,如果您是一位刚接触Linux的新手,这里的介绍可能对您有所帮助,如果您是以为Linux使用前辈,也可以在评论处留下您宝贵意见和经验,以便让更多 ...

  6. 【转】Android的setTag

    前言 首先我们要知道setTag方法是干什么的,SDK解释为 Tags Unlike IDs, tags are not used to identify views. Tags are essent ...

  7. UTF8与ANSI互转

    在取回的结果中,如果有Unicode字符,用printf来打印的话,则会出现乱码.通过这个方法,可以判断是否为unicode字符,是的话,通过wprintf来打印.1.判断字符串是否为Unicode的 ...

  8. GPU计算的后CUDA时代-OpenACC(转)

    在西雅图超级计算大会(SC11)上发布了新的基于指令的加速器并行编程标准,既OpenACC.这个开发标准的目的是让更多的编程人员可以用到GPU计算,同时计算结果可以跨加速器使用,甚至能用在多核CPU上 ...

  9. TSMessages,非HUD风格的iOS提示框(附官方demo BUG修复方案)

    优势 先看效果 个人觉得这种提示效果用在UITableView上要比HUD优雅美观,而其他情况下的提示,用HUD比较好 源码简介易懂,用起来也很方便 导入 pod导入相对很简单,主要讲怎么手动导入这个 ...

  10. SSI框架下,用jxl实现导出功能

    SSI框架下,用jxl实现导出功能 先说明一下,这个是SSI框架下,前端用ExtJs,应用在一个企业级的系统中的导出功能,因为是摸索着做的,所以里面有一些代码想整理一下,如果有人看到了,请视自己的架构 ...