MarginLayoutParams是和外间距有关的。和LayoutParams相比,MarginLayoutParams只是添加了对上下左右外间距的支持。实际上大部分LayoutParams的实现类都是继承自MarginLayoutParams,由于基本所有的父容器都是支持子View设置外间距的。
3.3.假如是WRAP_CONTENT
public static final int WRAP_CONTENT = -2;
/** * 重载方法1:增加一个子View * 假如这个子View还没有LayoutParams,就为子View设置当前ViewGroup默认的LayoutParams * * @param child */@Overridepublic void addView(View child) { addView(child, -1);} /** * 重载方法2:在指定位置增加一个子View * 假如这个子View还没有LayoutParams,就为子View设置当前ViewGroup默认的LayoutParams * * @param child * @param index View将在ViewGroup中被增加的位置(-1代表增加到末尾) */@Overridepublic void addView(View child, int index) { if (child == null) { throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); } LayoutParams params = child.getLayoutParams(); if (params == null) { params = generateDefaultLayoutParams(); if (params == null) { throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null"); } } addView(child, index, params);} /** * 重载方法3:增加一个子View * 使用当前ViewGroup默认的LayoutParams * * @param child * @param width 传入参数作为LayoutParams的width * @param height 传入参数作为LayoutParams的height */@Overridepublic void addView(View child, int width, int height) { final LayoutParams params = generateDefaultLayoutParams(); params.width = width; params.height = height; addView(child, -1, params);} /** * 重载方法4:增加一个子View * * @param child * @param params 使用传入的LayoutParams */@Overridepublic void addView(View child, LayoutParams params) { addView(child, -1, params);} /** * 重载方法5:增加一个子View, * * @param child * @param index View将在ViewGroup中被增加的位置 * @param params 使用传入的LayoutParams */@Overridepublic void addView(View child, int index, LayoutParams params) { super.addView(child, index, params);}
protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);}
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p != null; }
@Overrideprotected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof LinearLayout.LayoutParams;}
源码我们能看到定义
@Overrideprotected void onMeasure(intwidthMeasureSpec,intheightMeasureSpec){ //取出宽度确实切数值 int widthsizeMeasureSpec.getSize(widthMeasureSpec); //取出宽度的测量模式 int widthmodeMeasureSpec.getMode(widthMeasureSpec); //取出高度确实切数值 int heightsizeMeasureSpec.getSize(heightMeasureSpec); //取出高度的测量模式 int heightmodeMeasureSpec.getMode(heightMeasureSpec);}
模式 | 二进制的值 | 形容 |
---|---|---|
UNSPECIFIED | 00 | 默认值,父控件没有给子view任何限制,子View可以设置为任意大小。 |
EXACTLY | 01 | 表示父控件已经确切的指定了子View的大小。 |
AT_MOST | 10 | 表示子View具体大小没有尺寸限制,但是存在上限,上限一般为父View大小。 |
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) { //子view的布局参数也是确定大小,那子view模式就是准确模式 resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. //子view是MATCH_PARENT,那也是准确模式,父布局多大,子view就多大 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. //子view是WRAP_CONTENT,那最大不能超过父布局的大小,就为AT_MOST resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; 。 。 。 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}
Android 开发艺术这书里面这张图大家应该都看过
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //父布局的宽高 int viewGroupWidth = MeasureSpec.getSize(widthMeasureSpec); int viewGroupHeight = MeasureSpec.getSize(heightMeasureSpec); //遍历所有子View for (int i = 0; i < getChildCount(); i++) { View childView = getChildAt(i); //假如view可见 if (childView.getVisibility() == View.VISIBLE) { //子view的布局参数 LayoutParams childLayoutParams = childView.getLayoutParams(); //子view的measureSpec,传入父布局的measureSpec,还有父布局设置的内边距,子view的大小(大于0就是确定的大小,-1是match_parent,-2是wrap_content) int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, leftPadding + rightPadding, childLayoutParams.width); int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, topPadding + bottomPadding, childLayoutParams.height); //子view调用了measure才能得出确切的宽高 childView.measure(childWidthMeasureSpec, childHeightMeasureSpec); //子View的宽高 int childMeasureWidth = childView.getMeasuredWidth(); int childMeasureHeight = childView.getMeasuredHeight(); } //再测量ViewGroup int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int realWidth = widthMode == MeasureSpec.EXACTLY ? viewGroupWidth : viewGroupNeedWidth; int realHeight = heightMode == MeasureSpec.EXACTLY ? viewGroupHeight : viewGroupNeedHeight; setMeasuredDimension(realWidth, realHeight);}