通过重写ViewGroup学习onMeasure()和onLayout()方法
在继承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:
package net.loonggg.viewgroup; import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup; public class MyViewGroup extends ViewGroup { public MyViewGroup(Context context) {
super(context);
} public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
} public MyViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} /**
* 计算控件的大小
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measureWidth = measureWidth(widthMeasureSpec);
int measureHeight = measureHeight(heightMeasureSpec);
// 计算自定义的ViewGroup中所有子控件的大小
measureChildren(widthMeasureSpec, heightMeasureSpec);
// 设置自定义的控件MyViewGroup的大小
setMeasuredDimension(measureWidth, measureHeight);
} private int measureWidth(int pWidthMeasureSpec) {
int result = 0;
int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 得到模式
int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 得到尺寸 switch (widthMode) {
/**
* 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方法传入的模式。
*/
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = widthSize;
break;
}
return result;
} private int measureHeight(int pHeightMeasureSpec) {
int result = 0; int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
int heightSize = MeasureSpec.getSize(pHeightMeasureSpec); switch (heightMode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = heightSize;
break;
}
return result;
} /**
* 覆写onLayout,其目的是为了指定视图的显示位置,方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下,
* 才能确定怎么摆放
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 记录总高度
int mTotalHeight = 0;
// 遍历所有子视图
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i); // 获取在onMeasure中计算的视图尺寸
int measureHeight = childView.getMeasuredHeight();
int measuredWidth = childView.getMeasuredWidth(); childView.layout(l, mTotalHeight, measuredWidth, mTotalHeight
+ measureHeight); mTotalHeight += measureHeight; }
} }
第二步,布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00f0f0"
tools:context=".MainActivity" > <net.loonggg.viewgroup.MyViewGroup
android:id="@+id/myViewGroup"
android:layout_width="480dp"
android:layout_height="300dp"
android:background="#0f0f0f" > <TextView
android:layout_width="200dp"
android:layout_height="100dp"
android:background="#000000"
android:gravity="center"
android:text="第一个TextView" /> <TextView
android:layout_width="100dp"
android:layout_height="200dp"
android:background="#ffffff"
android:gravity="center"
android:text="第二个TextView" />
</net.loonggg.viewgroup.MyViewGroup> </RelativeLayout>
第三步,MainActivity.java:
package net.loonggg.viewgroup; import android.os.Bundle;
import android.app.Activity; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} }
ok,你们大家懂了吗?有问题请留言。
通过重写ViewGroup学习onMeasure()和onLayout()方法的更多相关文章
- 继承ViewGroup学习onMeasure()和onLayout()方法
在继承ViewGroup类时,需要重写两个方法,分别是onMeasure和onLayout. 1,在方法onMeasure中调用setMeasuredDimension方法void android.v ...
- 【转】ViewGroup的onMeasure和onLayout分析
ViewGroup的onMeasure和onLayout分析 一个Viewgroup基本的继承类格式如下: 1 import android.content.Context; 2 import and ...
- Android的onMeasure和onLayout And MeasureSpec揭秘
Android中自定义ViewGroup最重要的就是onMeasure和onLayout方法,都需要重写这两个方法,ViewGroup绘制 的过程是这样的:onMeasure → onLayout → ...
- 自定义控件详解(五):onMeasure()、onLayout()
前言: 自定义控件的三大方法: 测量: onMeasure(): 测量自己的大小,为正式布局提供建议 布局: onLayout(): 使用layout()函数对所有子控件布局 绘制: onDraw() ...
- 自定义ViewGroup基础巩固1---理解onLayout()方法
自定义ViewGroup这个是在android中自定义控件中不可获缺的很重要的一部分,关于它的意义这里就不过多阐述了,为了在未来深入上继续走下去,所以先把基础给打牢. 这篇主要是理解ViewGroup ...
- java===java基础学习(12)---方法的重写和重载
覆盖 / 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为. 也 ...
- C#基础知识学习(1)方法的重写和隐藏
做了1年多了C#,发现些项目过程中很多基础东西都不是很清晰,基础不够牢固.现在开始复习基础知识并做重点记录 方法需要被重写的时候,可以在方法前加入virtual使方法变成虚方法. 这样我们可以重新写个 ...
- Android开发之View重写相关API-onLayout,onMeasure,MeasureSpec
1.onLayout android.view.ViewGroup protected void onLayout(boolean changed, int l, int t, int r, int ...
- 对于view的深入理解,续篇(一)重写ViewGroup的onDraw
在上一篇文章中,不仅熟悉了动态设定布局的方法,而且也对view的绘制流程有所了解.于是我继续做了下面几个实验,发现了一个问题.如果对view的绘制流程不是很明白,可以看看我的上一篇文章的介绍,点击下面 ...
随机推荐
- 起一个node服务
使用node开发一个应用,非常简单,甚至都不用去配置一堆文件来启动一个webu服务器,直接去官网把这一段示例代码拷过来 https://nodejs.org/en/about/ 中文网没有这个abou ...
- maven parent version not found
需要把parent工程,也就是package是pom的那个工程先install一下 要是不行的话可以试下mvn -X clean install,-X表示强制从远程库更新dependency:再不行可 ...
- Mac 修改用户环境变量
Mac 修改用户环境变量 sudo vim ~/.bash_profile
- AI-Info-Micron-Insight:5G、人工智能和即将到来的移动革命
ylbtech-AI-Info-Micron-Insight:5G.人工智能和即将到来的移动革命 1.返回顶部 1. 5G.人工智能和即将到来的移动革命 人们都说自己的手机“智能”,但究竟有多智能?凡 ...
- C# 方法中的参数类型
二.方法中的参数类型 1. 值参数 值参数是指不带修饰符只带数据类型的形参. 值参数在使用值向方法传递参数时,编译程序会把实参的值做一份拷贝,并且将此拷贝传递给该方法,被调用的方法不会修改内存中实参的 ...
- Git工作流指南:功能分支工作流(转)
一旦你玩转了集中式工作流,在开发过程中可以很简单地加上功能分支,用来鼓励开发者之间协作和简化交流. 功能分支工作流背后的核心思路是所有的功能开发应该在一个专门的分支,而不是在master分支上.这个隔 ...
- 写给iOS小白的MVVM教程(序)
这几天,需要重构下部分代码,这里简要记录下.但是涉及的技术要点还是很多,所以分为多个篇章叙述.此教程来源于,并将于应用于实践,不做过多的概念性阐释和争论.每个篇章都会附上实际的可执行的代码.因涉及的技 ...
- codeforces757E. Bash Plays with Functions(狄利克雷卷积 积性函数)
http://codeforces.com/contest/757/problem/E 题意 Sol 非常骚的一道题 首先把给的式子化一下,设$u = d$,那么$v = n / d$ $$f_r(n ...
- springMVC-数据绑定
定义: 将http请求中参数绑定到Handler业务方法 常用数据绑定类型 1. 基本数据类型 不能为其它类型和null值 2. 包装类 可以为其它对象,全部转成null值 3. 数组 多个对象 ...
- GUI测试问题汇总
1.ajax实现的页面元素定位问题 最近在做项目的时候遇到一个问题,通过xpath定位到元素后做一个循环操作,第一循环可以正常执行,第二次循环后就报错,错误信息:Message: The elemen ...