View onMeasure测量过程解析
2017-11-26 13:24
337 查看
参考文章:
Android自定义View:MeasureSpec的真正意义与View大小控制
源码解析Android中View的measure量算过程
布局测量过程:
1.generateLayoutParams(AttributeSet attrs)
系统加载xml布局文件时,会调用这个方法生成LayoutParams。
ViewGroup中有三种生成LayoutParams的方法,自定义Layout中如果也自定义了LayoutParams,必须要重写这个三个方法,如果想自定义layout可以参考FrameLayout。
2.顶层布局通过调用View.measure(int widthMeasureSpec, int heightMeasureSpec),这个方法是final,
在该方法中会调用onMeasure(int widthMeasureSpec, int heightMeasureSpec),这个是实际测量方法,所有子类都必须实现这个方法实现自己的测量方案。
子类在实现该方法中调用measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)
或者measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed),这两个方法实现
原理一样,都是调用View.measure(int widthMeasureSpec, int heightMeasureSpec)实现对childView的测量,这样就实现了嵌套测量。
**子类是可以重写这两个方法已实现自己的对childView的测量方式,目前只有几个ScrollView重写了两个方法。当然子类也可以不调用这两个方法,自己实现,其实很简单,主要是根据LayoutParams、padding、margin等调用getChildMeasureSpec(int spec, int padding, int childDimension)方法生成childMeasureSpec,然后调用child.measure(childWidthMeasureSpec, childHeightMeasureSpec); **
3.在getChildMeasureSpec(int spec, int padding, int childDimension)方法中可以很清楚的看见父布局是
怎样生成对childView的约束的childWidthMeasureSpec。
4.onMeasure方法最后都需要调用setMeasuredDimension(int measuredWidth, int measuredHeight)方法设置测量结果才能生效,**自定义Layout中在调用该方法之前最好调用resolveSizeAndState方法生成正确的尺寸,**参考FrameLayout的onMeasure方法。
5.MeasureSpec.UNSPECIFIED未对childView做限制,可以随意大小,一般是ScrollView、AdapterView等在重写measureChildWithMargins和measureChild方法中传给childView。
Android自定义View:MeasureSpec的真正意义与View大小控制
源码解析Android中View的measure量算过程
布局测量过程:
1.generateLayoutParams(AttributeSet attrs)
系统加载xml布局文件时,会调用这个方法生成LayoutParams。
ViewGroup中有三种生成LayoutParams的方法,自定义Layout中如果也自定义了LayoutParams,必须要重写这个三个方法,如果想自定义layout可以参考FrameLayout。
public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } /** * Returns a safe set of layout parameters based on the supplied layout params. * When a ViewGroup is passed a View whose layout params do not pass the test of * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method * is invoked. This method should return a new set of layout params suitable for * this ViewGroup, possibly by copying the appropriate attributes from the * specified set of layout params. * * @param p The layout parameters to convert into a suitable set of layout parameters * for this ViewGroup. * * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one * of its descendants */ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return p; } /** * Returns a set of default layout parameters. These parameters are requested * when the View passed to {@link #addView(View)} has no layout parameters * already set. If null is returned, an exception is thrown from addView. * * @return a set of default layout parameters or null */ protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); }
2.顶层布局通过调用View.measure(int widthMeasureSpec, int heightMeasureSpec),这个方法是final,
在该方法中会调用onMeasure(int widthMeasureSpec, int heightMeasureSpec),这个是实际测量方法,所有子类都必须实现这个方法实现自己的测量方案。
子类在实现该方法中调用measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)
或者measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed),这两个方法实现
原理一样,都是调用View.measure(int widthMeasureSpec, int heightMeasureSpec)实现对childView的测量,这样就实现了嵌套测量。
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); } protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
**子类是可以重写这两个方法已实现自己的对childView的测量方式,目前只有几个ScrollView重写了两个方法。当然子类也可以不调用这两个方法,自己实现,其实很简单,主要是根据LayoutParams、padding、margin等调用getChildMeasureSpec(int spec, int padding, int childDimension)方法生成childMeasureSpec,然后调用child.measure(childWidthMeasureSpec, childHeightMeasureSpec); **
3.在getChildMeasureSpec(int spec, int padding, int childDimension)方法中可以很清楚的看见父布局是
怎样生成对childView的约束的childWidthMeasureSpec。
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; } //noinspection ResourceType return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }
4.onMeasure方法最后都需要调用setMeasuredDimension(int measuredWidth, int measuredHeight)方法设置测量结果才能生效,**自定义Layout中在调用该方法之前最好调用resolveSizeAndState方法生成正确的尺寸,**参考FrameLayout的onMeasure方法。
5.MeasureSpec.UNSPECIFIED未对childView做限制,可以随意大小,一般是ScrollView、AdapterView等在重写measureChildWithMargins和measureChild方法中传给childView。
相关文章推荐
- Android自定义View(三、深入解析控件测量onMeasure)
- Android自定义View(三、深入解析控件测量onMeasure)
- Android自定义View(三、深入解析控件测量onMeasure)
- (转)Android自定义View(三、深入解析控件测量onMeasure)
- [置顶] Android自定义View(三、深入解析控件测量onMeasure)
- Android 自定义View 之测量过程(onMeasure)
- FrameLayout measure过程源码Log全解析之四:onMeasure第一部分之ViewGroup对view的管理
- Android中View的绘制过程 onMeasure方法简述
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- 自定义View精炼详解第(四)课:onMeasure()解析和简单示例
- Android View 测量流程(Measure)完全解析
- view工作原理-计算视图大小的过程(onMeasure)
- 【转】Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- Android 自定义View 测量控件大小onMeasure中MeasureSpec作用
- Android View中onMeasure的相关解析
- View学习(二)-View的测量(measure)过程
- Android View 测量流程(Measure)完全解析
- Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
- 源码解析Android中View的measure量算过程
- Android View 测量流程(Measure)全面解析