Android onMeasure方法
来源:互联网 发布:九宫图算法口诀 编辑:程序博客网 时间:2024/06/06 03:36
Android onMeasure方法
1、View.onMeasure方法
View中的onMeasure方法调用setMeasuredDimension方法来设置实际的宽和高,使用getDefaultSize方法获取默认的宽高。在自定义控件中也可以使用setMeasuredDimension来设置宽高。
(1) onMeasure方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}(2) getDefaultSize方法
在getDefaultSize方法中,使用MeasureSpec来获取mode和size,并返回计算后的值。
当mode为UNSPECIFIED时,返回默认值,否则返回建议值。
public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result;}(3) MeasureSpec
MeasureSpec有三种类型,UNSPECIFIED、EXACTLY和AT_MOST。
UNSPECIFIED表示未定义,即父控件未做限制,可以为任何值,一般设置为0。
EXACTLY表示实际值,即父容器已经指定了具体的值。
AT_MOST表示父容器提供了最大值,但子控件可以选择自己的范围。
使用静态方法来获取实际的mode和size
public static int getMode(int measureSpec)public static int getSize(int measureSpec)(4) 自定义控件CMeasureView,获取实际的size和mode值。
public class CMeasureView extends View {private final static String LOGTAG = "CMeasureView";public CMeasureView(Context context) {super(context);}public CMeasureView(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int mode = MeasureSpec.getMode(widthMeasureSpec);int size = MeasureSpec.getSize(widthMeasureSpec);LogUtil.log(LOGTAG, "width = " + size + " mode = " + getMode(mode));mode = MeasureSpec.getMode(heightMeasureSpec);size = MeasureSpec.getSize(heightMeasureSpec);LogUtil.log(LOGTAG, "height = " + size + " mode = " + getMode(mode));}private String getMode(int mode) {if (mode == MeasureSpec.UNSPECIFIED) {return "UNSPECIFIED";} else if (mode == MeasureSpec.AT_MOST) {return "AT_MOST";} else if (mode == MeasureSpec.EXACTLY) {return "EXACTLY";} else {return "unknow mode";}}}(5) 布局文件activity_measure.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.blog.demo.control.CMeasureView android:layout_width="match_parent" android:layout_height="@dimen/margin_xdpi_30" /> <com.blog.demo.control.CMeasureView android:layout_width="wrap_content" android:layout_height="wrap_content" /></LinearLayout>我们可以看到,当宽高指定大小或者为match_parent时,mode为EXACTLY。当宽高为wrap_parent时,mode为AT_MOST。
2、ViewGroup.onMeasure的用法
ViewGroup除了需要计算自身的宽高以外,还要计算子控件的宽高,系统提供了measureChildren、measureChild和getChildMeasureSpec来支持一般的操作。(1) measureChildren方法
只要child的Visibility不是GONE,就计算child的宽高,调用measureChild方法。
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) { final int size = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < size; ++i) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } }}(2) measureChild方法
使用getChildMeasureSpec方法获得宽高,最后调用View.measure方法设置。
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec);}(3) getChildMeasureSpec方法
public static int getChildMeasureSpec(int spec, int padding, int childDimension) { int specMode = MeasureSpec.getMode(spec); int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); int resultSize = 0; int resultMode = 0; switch (specMode) { // Parent has imposed an exact size on us case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent has imposed a maximum size on us case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size, but our size is not fixed. // Constrain child to not be bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent asked to see how big we want to be case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size; resultMode = MeasureSpec.UNSPECIFIED; } break; } return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}
3、自定义CMeasureViewGroup
(1) 自定义onMeasure方法调用getMeasureSize方法获取size,并设置控件的宽高,并且记得调用measureChildren方法来计算子控件的宽高,否则子控件无法显示。同时需要实现onLayout方法,用来计算子控件的位置。
public class CMeasureViewGroup extends ViewGroup {private final static String LOGTAG = "CMeasureViewGroup";public CMeasureViewGroup(Context context) {super(context);}public CMeasureViewGroup(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = getMeasureSize(widthMeasureSpec);int height = getMeasureSize(heightMeasureSpec);setMeasuredDimension(width, height);measureChildren(widthMeasureSpec, heightMeasureSpec);}private int getMeasureSize(int measureSpec) {int mode = MeasureSpec.getMode(measureSpec);int size = MeasureSpec.getSize(measureSpec);LogUtil.log(LOGTAG, "size = " + size + " mode = " + getMode(mode));if (mode == MeasureSpec.UNSPECIFIED) {return 0;} else if (mode == MeasureSpec.AT_MOST ||mode == MeasureSpec.EXACTLY) {return size;} else {return 0;}}private String getMode(int mode) {if (mode == MeasureSpec.UNSPECIFIED) {return "UNSPECIFIED";} else if (mode == MeasureSpec.AT_MOST) {return "AT_MOST";} else if (mode == MeasureSpec.EXACTLY) {return "EXACTLY";} else {return "unknow mode";}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {LogUtil.log(LOGTAG, "left = " + l + " top = " + t + " right = " + r + " bottom = " + b);int totalHeight = t;int childCount = getChildCount();for (int i = 0; i < childCount; i++) {View child = getChildAt(i);int measureWidth = child.getMeasuredWidth();int measureHeight = child.getMeasuredHeight();child.layout(l, totalHeight, l + measureWidth, totalHeight + measureHeight);totalHeight += measureHeight;}}}(2) 布局文件activity_measure_viewgroup.xml
<?xml version="1.0" encoding="utf-8"?><com.blog.demo.control.CMeasureViewGroup xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.blog.demo.control.CMeasureView android:layout_width="@dimen/margin_xdpi_30" android:layout_height="@dimen/margin_xdpi_30" android:background="#ffff0000" /><com.blog.demo.control.CMeasureView android:layout_width="match_parent" android:layout_height="@dimen/margin_xdpi_30" android:background="#ff0000ff" /> <com.blog.demo.control.CMeasureView android:layout_width="wrap_content" android:layout_height="@dimen/margin_xdpi_30" android:background="#ff00ff00" /></com.blog.demo.control.CMeasureViewGroup>
在系统日志中可以看到CMeasureViewGroup和CMeasureView的实际宽高。
(3) 显示结果如下
0 0
- Android View onMeasure 方法
- Android onMeasure方法介绍
- Android onMeasure方法介绍
- Android View.onMeasure方法
- Android onMeasure方法介绍
- Android的onMeasure方法
- Android onMeasure方法介绍
- Android onMeasure方法介绍
- android 的onMeasure方法
- Android onMeasure() 方法翻译
- Android onMeasure方法
- 关于Android中onMeasure方法
- Android onMeasure,onFocusChanged方法介绍
- Android之View.onMeasure方法
- android笔记之onMeasure方法
- Android中onMeasure方法详解
- Android之View.onMeasure()方法
- Android View.onMeasure方法的理解
- SpringMVC框架学习(2)--SpringMVC和Mybatis的整合
- git commit 如何修改上一个commit以及合并最近两个commit
- mac上如何让终端翻墙
- 鸟哥Linux私房菜_笔记_Chapter3
- CocoaPods的安装和使用
- Android onMeasure方法
- C语言入门(二十二)堆和链表
- Android调用系统相册和相机选择图片并显示在imageview中
- jQuery基础学习(一)
- 多次presentViewController后,直接返回到初始的viewcontroller
- MySQL中删除表中重复数据,只保留一条
- CocoaPods pod install/pod update更新慢的问题
- 串算法 - KMP算法
- java中object...类型