简单研究Android View绘制二 LayoutParams
2015-07-28 17:23:20
本篇是关于LayoutParams相关
ViewGroup.LayoutParams文档解释如下:
LayoutParams are used by views to tell their parents how they want to be laid out. See ViewGroup Layout Attributes
for a list of all child view attributes that this class supports.
The base LayoutParams class just describes how big the view wants to be for both width and height. For each dimension, it can specify one of:
- FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which means that the view wants to be as big as its parent (minus padding)
- WRAP_CONTENT, which means that the view wants to be just big enough to enclose its content (plus padding)
- an exact number
There are subclasses of LayoutParams for different subclasses of ViewGroup. For example, AbsoluteLayout has its own subclass of LayoutParams which adds an X and Y value.
翻译过来,大意是:LayoutParams经常用于view告诉它的父控件如何摆放它。此父类只申明了view想要多大的宽和高,值为FILL_PARENT、WRAP_CONTENT或者一个精确值。ViewGroup的子类大都有自己的、继承自该类的子类,比如AbsoluteLayout有自己的LayoutParams子类,并且多了x和y两个属性。
OK,我们至少明白一点,那就是LayoutParams是view用来告诉他的父控件如何摆放他的属性集合,比如宽、高、是否居中等。所以LayoutParams被设计为ViewGroup的内部类,而且每一个继承自ViewGroup的子类,都会继承并重写ViewGroup的LayoutParams类,毕竟每个布局类实现的效果不一样,所使用的参数、属性等也就不一样,所以需要重写。比如LineatLayout中可以使用weight,但是RelativeLayout中并无此属性。
现在来看看ViewGroup中LayoutParams的源码:
/**
* LayoutParams are used by views to tell their parents how they want to be
* laid out. See
* {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
* for a list of all child view attributes that this class supports.
*
* <p>
* The base LayoutParams class just describes how big the view wants to be
* for both width and height. For each dimension, it can specify one of:
* <ul>
* <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
* means that the view wants to be as big as its parent (minus padding)
* <li> WRAP_CONTENT, which means that the view wants to be just big enough
* to enclose its content (plus padding)
* <li> an exact number
* </ul>
* There are subclasses of LayoutParams for different subclasses of
* ViewGroup. For example, AbsoluteLayout has its own subclass of
* LayoutParams which adds an X and Y value.</p>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about creating user interface layouts, read the
* <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
* guide.</p></div>
*
* @attr ref android.R.styleable#ViewGroup_Layout_layout_height
* @attr ref android.R.styleable#ViewGroup_Layout_layout_width
*/
public static class LayoutParams {
/**
* Special value for the height or width requested by a View.
* FILL_PARENT means that the view wants to be as big as its parent,
* minus the parent's padding, if any. This value is deprecated
* starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
*/
@SuppressWarnings({"UnusedDeclaration"})
@Deprecated
public static final int FILL_PARENT = -1; /**
* Special value for the height or width requested by a View.
* MATCH_PARENT means that the view wants to be as big as its parent,
* minus the parent's padding, if any. Introduced in API Level 8.
*/
public static final int MATCH_PARENT = -1; /**
* Special value for the height or width requested by a View.
* WRAP_CONTENT means that the view wants to be just large enough to fit
* its own internal content, taking its own padding into account.
*/
public static final int WRAP_CONTENT = -2; /**
* Information about how wide the view wants to be. Can be one of the
* constants FILL_PARENT (replaced by MATCH_PARENT ,
* in API Level 8) or WRAP_CONTENT. or an exact size.
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
@ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
})
public int width; /**
* Information about how tall the view wants to be. Can be one of the
* constants FILL_PARENT (replaced by MATCH_PARENT ,
* in API Level 8) or WRAP_CONTENT. or an exact size.
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
@ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
})
public int height; /**
* Used to animate layouts.
*/
public LayoutAnimationController.AnimationParameters layoutAnimationParameters; /**
* Creates a new set of layout parameters. The values are extracted from
* the supplied attributes set and context. The XML attributes mapped
* to this set of layout parameters are:
*
* <ul>
* <li><code>layout_width</code>: the width, either an exact value,
* {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
* {@link #MATCH_PARENT} in API Level 8)</li>
* <li><code>layout_height</code>: the height, either an exact value,
* {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
* {@link #MATCH_PARENT} in API Level 8)</li>
* </ul>
*
* @param c the application environment
* @param attrs the set of attributes from which to extract the layout
* parameters' values
*/
public LayoutParams(Context c, AttributeSet attrs) {
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
setBaseAttributes(a,
R.styleable.ViewGroup_Layout_layout_width,
R.styleable.ViewGroup_Layout_layout_height);
a.recycle();
} /**
* Creates a new set of layout parameters with the specified width
* and height.
*
* @param width the width, either {@link #WRAP_CONTENT},
* {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
* API Level 8), or a fixed size in pixels
* @param height the height, either {@link #WRAP_CONTENT},
* {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
* API Level 8), or a fixed size in pixels
*/
public LayoutParams(int width, int height) {
this.width = width;
this.height = height;
} /**
* Copy constructor. Clones the width and height values of the source.
*
* @param source The layout params to copy from.
*/
public LayoutParams(LayoutParams source) {
this.width = source.width;
this.height = source.height;
} /**
* Used internally by MarginLayoutParams.
* @hide
*/
LayoutParams() {
} /**
* Extracts the layout parameters from the supplied attributes.
*
* @param a the style attributes to extract the parameters from
* @param widthAttr the identifier of the width attribute
* @param heightAttr the identifier of the height attribute
*/
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
width = a.getLayoutDimension(widthAttr, "layout_width");
height = a.getLayoutDimension(heightAttr, "layout_height");
} /**
* Resolve layout parameters depending on the layout direction. Subclasses that care about
* layoutDirection changes should override this method. The default implementation does
* nothing.
*
* @param layoutDirection the direction of the layout
*
* {@link View#LAYOUT_DIRECTION_LTR}
* {@link View#LAYOUT_DIRECTION_RTL}
*/
public void resolveLayoutDirection(int layoutDirection) {
} /**
* Returns a String representation of this set of layout parameters.
*
* @param output the String to prepend to the internal representation
* @return a String with the following format: output +
* "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
*
* @hide
*/
public String debug(String output) {
return output + "ViewGroup.LayoutParams={ width="
+ sizeToString(width) + ", height=" + sizeToString(height) + " }";
} /**
* Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
*
* @param view the view that contains these layout parameters
* @param canvas the canvas on which to draw
*
* @hide
*/
public void onDebugDraw(View view, Canvas canvas, Paint paint) {
} /**
* Converts the specified size to a readable String.
*
* @param size the size to convert
* @return a String instance representing the supplied size
*
* @hide
*/
protected static String sizeToString(int size) {
if (size == WRAP_CONTENT) {
return "wrap-content";
}
if (size == MATCH_PARENT) {
return "match-parent";
}
return String.valueOf(size);
}
}
可以看到,在所有LayoutParams的祖宗类ViewGroup.LayoutParams中只定义了两个最最基本的属性:width和height,这两个属性是在哪定义的呢?R.styleable.ViewGroup_Layout_layout_width和R.styleable.ViewGroup_Layout_layout_height,它们是在frameworks/base/core/res/res/values/attrs.xml中定义的,这和我们自定义View时添加自己属性的方式是一样的。
其实ViewGroup中并不只提供了这一种LayoutParams,还有一个叫MarginLayoutParams,源码如下:
/**
* Per-child layout information for layouts that support margins.
* See
* {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
* for a list of all child view attributes that this class supports.
*/
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
/**
* The left margin in pixels of the child.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int leftMargin; /**
* The top margin in pixels of the child.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int topMargin; /**
* The right margin in pixels of the child.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int rightMargin; /**
* The bottom margin in pixels of the child.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int bottomMargin; /**
* The start margin in pixels of the child.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
private int startMargin = DEFAULT_MARGIN_RELATIVE; /**
* The end margin in pixels of the child.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
private int endMargin = DEFAULT_MARGIN_RELATIVE; /**
* The default start and end margin.
* @hide
*/
public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE; /**
* Bit 0: layout direction
* Bit 1: layout direction
* Bit 2: left margin undefined
* Bit 3: right margin undefined
* Bit 4: is RTL compatibility mode
* Bit 5: need resolution
*
* Bit 6 to 7 not used
*
* @hide
*/
@ViewDebug.ExportedProperty(category = "layout", flagMapping = {
@ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
@ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
@ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
@ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
@ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
})
byte mMarginFlags; private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
private static final int NEED_RESOLUTION_MASK = 0x00000020; private static final int DEFAULT_MARGIN_RESOLVED = 0;
private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE; /**
* Creates a new set of layout parameters. The values are extracted from
* the supplied attributes set and context.
*
* @param c the application environment
* @param attrs the set of attributes from which to extract the layout
* parameters' values
*/
public MarginLayoutParams(Context c, AttributeSet attrs) {
super(); TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
setBaseAttributes(a,
R.styleable.ViewGroup_MarginLayout_layout_width,
R.styleable.ViewGroup_MarginLayout_layout_height); int margin = a.getDimensionPixelSize(
com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
if (margin >= 0) {
leftMargin = margin;
topMargin = margin;
rightMargin= margin;
bottomMargin = margin;
} else {
leftMargin = a.getDimensionPixelSize(
R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
UNDEFINED_MARGIN);
if (leftMargin == UNDEFINED_MARGIN) {
mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
leftMargin = DEFAULT_MARGIN_RESOLVED;
}
rightMargin = a.getDimensionPixelSize(
R.styleable.ViewGroup_MarginLayout_layout_marginRight,
UNDEFINED_MARGIN);
if (rightMargin == UNDEFINED_MARGIN) {
mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
rightMargin = DEFAULT_MARGIN_RESOLVED;
} topMargin = a.getDimensionPixelSize(
R.styleable.ViewGroup_MarginLayout_layout_marginTop,
DEFAULT_MARGIN_RESOLVED);
bottomMargin = a.getDimensionPixelSize(
R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
DEFAULT_MARGIN_RESOLVED); startMargin = a.getDimensionPixelSize(
R.styleable.ViewGroup_MarginLayout_layout_marginStart,
DEFAULT_MARGIN_RELATIVE);
endMargin = a.getDimensionPixelSize(
R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
DEFAULT_MARGIN_RELATIVE); if (isMarginRelative()) {
mMarginFlags |= NEED_RESOLUTION_MASK;
}
} final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
} // Layout direction is LTR by default
mMarginFlags |= LAYOUT_DIRECTION_LTR; a.recycle();
} /**
* {@inheritDoc}
*/
public MarginLayoutParams(int width, int height) {
super(width, height); mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK; mMarginFlags &= ~NEED_RESOLUTION_MASK;
mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
} /**
* Copy constructor. Clones the width, height and margin values of the source.
*
* @param source The layout params to copy from.
*/
public MarginLayoutParams(MarginLayoutParams source) {
this.width = source.width;
this.height = source.height; this.leftMargin = source.leftMargin;
this.topMargin = source.topMargin;
this.rightMargin = source.rightMargin;
this.bottomMargin = source.bottomMargin;
this.startMargin = source.startMargin;
this.endMargin = source.endMargin; this.mMarginFlags = source.mMarginFlags;
} /**
* {@inheritDoc}
*/
public MarginLayoutParams(LayoutParams source) {
super(source); mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK; mMarginFlags &= ~NEED_RESOLUTION_MASK;
mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
} /**
* Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
* to be done so that the new margins are taken into account. Left and right margins may be
* overriden by {@link android.view.View#requestLayout()} depending on layout direction.
*
* @param left the left margin size
* @param top the top margin size
* @param right the right margin size
* @param bottom the bottom margin size
*
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
*/
public void setMargins(int left, int top, int right, int bottom) {
leftMargin = left;
topMargin = top;
rightMargin = right;
bottomMargin = bottom;
mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
if (isMarginRelative()) {
mMarginFlags |= NEED_RESOLUTION_MASK;
} else {
mMarginFlags &= ~NEED_RESOLUTION_MASK;
}
} /**
* Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
* needs to be done so that the new relative margins are taken into account. Left and right
* margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
* direction.
*
* @param start the start margin size
* @param top the top margin size
* @param end the right margin size
* @param bottom the bottom margin size
*
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
*
* @hide
*/
public void setMarginsRelative(int start, int top, int end, int bottom) {
startMargin = start;
topMargin = top;
endMargin = end;
bottomMargin = bottom;
mMarginFlags |= NEED_RESOLUTION_MASK;
} /**
* Sets the relative start margin.
*
* @param start the start margin size
*
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
*/
public void setMarginStart(int start) {
startMargin = start;
mMarginFlags |= NEED_RESOLUTION_MASK;
} /**
* Returns the start margin in pixels.
*
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
*
* @return the start margin in pixels.
*/
public int getMarginStart() {
if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
doResolveMargins();
}
switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
case View.LAYOUT_DIRECTION_RTL:
return rightMargin;
case View.LAYOUT_DIRECTION_LTR:
default:
return leftMargin;
}
} /**
* Sets the relative end margin.
*
* @param end the end margin size
*
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
*/
public void setMarginEnd(int end) {
endMargin = end;
mMarginFlags |= NEED_RESOLUTION_MASK;
} /**
* Returns the end margin in pixels.
*
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
*
* @return the end margin in pixels.
*/
public int getMarginEnd() {
if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
doResolveMargins();
}
switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
case View.LAYOUT_DIRECTION_RTL:
return leftMargin;
case View.LAYOUT_DIRECTION_LTR:
default:
return rightMargin;
}
} /**
* Check if margins are relative.
*
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
* @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
*
* @return true if either marginStart or marginEnd has been set.
*/
public boolean isMarginRelative() {
return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
} /**
* Set the layout direction
* @param layoutDirection the layout direction.
* Should be either {@link View#LAYOUT_DIRECTION_LTR}
* or {@link View#LAYOUT_DIRECTION_RTL}.
*/
public void setLayoutDirection(int layoutDirection) {
if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
if (isMarginRelative()) {
mMarginFlags |= NEED_RESOLUTION_MASK;
} else {
mMarginFlags &= ~NEED_RESOLUTION_MASK;
}
}
} /**
* Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
* {@link View#LAYOUT_DIRECTION_RTL}.
*
* @return the layout direction.
*/
public int getLayoutDirection() {
return (mMarginFlags & LAYOUT_DIRECTION_MASK);
} /**
* This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
* may be overridden depending on layout direction.
*/
@Override
public void resolveLayoutDirection(int layoutDirection) {
setLayoutDirection(layoutDirection); // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
// Will use the left and right margins if no relative margin is defined.
if (!isMarginRelative() ||
(mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return; // Proceed with resolution
doResolveMargins();
} private void doResolveMargins() {
if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
// if left or right margins are not defined and if we have some start or end margin
// defined then use those start and end margins.
if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
&& startMargin > DEFAULT_MARGIN_RELATIVE) {
leftMargin = startMargin;
}
if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
&& endMargin > DEFAULT_MARGIN_RELATIVE) {
rightMargin = endMargin;
}
} else {
// We have some relative margins (either the start one or the end one or both). So use
// them and override what has been defined for left and right margins. If either start
// or end margin is not defined, just set it to default "0".
switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
case View.LAYOUT_DIRECTION_RTL:
leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
endMargin : DEFAULT_MARGIN_RESOLVED;
rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
startMargin : DEFAULT_MARGIN_RESOLVED;
break;
case View.LAYOUT_DIRECTION_LTR:
default:
leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
startMargin : DEFAULT_MARGIN_RESOLVED;
rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
endMargin : DEFAULT_MARGIN_RESOLVED;
break;
}
}
mMarginFlags &= ~NEED_RESOLUTION_MASK;
} /**
* @hide
*/
public boolean isLayoutRtl() {
return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
} /**
* @hide
*/
@Override
public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE; fillDifference(canvas,
view.getLeft() + oi.left,
view.getTop() + oi.top,
view.getRight() - oi.right,
view.getBottom() - oi.bottom,
leftMargin,
topMargin,
rightMargin,
bottomMargin,
paint);
}
}
当然,他必须是继承自LayoutParams祖宗类的~MarginLayoutParams添加了好多属性,主要是用来设置margin值的。下面我们以LinearLayout和RelativeLayout为例,来看看它们是怎么定义自己的LayoutParams的。
LinearLayout.java
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
/**
* Indicates how much of the extra space in the LinearLayout will be
* allocated to the view associated with these LayoutParams. Specify
* 0 if the view should not be stretched. Otherwise the extra pixels
* will be pro-rated among all views whose weight is greater than 0.
*/
@ViewDebug.ExportedProperty(category = "layout")
public float weight; /**
* Gravity for the view associated with these LayoutParams.
*
* @see android.view.Gravity
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = -1, to = "NONE"),
@ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
@ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
@ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
@ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
@ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
@ViewDebug.IntToString(from = Gravity.START, to = "START"),
@ViewDebug.IntToString(from = Gravity.END, to = "END"),
@ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
@ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
@ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
@ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
@ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
@ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
})
public int gravity = -1; /**
* {@inheritDoc}
*/
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray a =
c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LinearLayout_Layout); weight = a.getFloat(com.android.internal.R.styleable.LinearLayout_Layout_layout_weight, 0);
gravity = a.getInt(com.android.internal.R.styleable.LinearLayout_Layout_layout_gravity, -1); a.recycle();
} /**
* {@inheritDoc}
*/
public LayoutParams(int width, int height) {
super(width, height);
weight = 0;
} /**
* Creates a new set of layout parameters with the specified width, height
* and weight.
*
* @param width the width, either {@link #MATCH_PARENT},
* {@link #WRAP_CONTENT} or a fixed size in pixels
* @param height the height, either {@link #MATCH_PARENT},
* {@link #WRAP_CONTENT} or a fixed size in pixels
* @param weight the weight
*/
public LayoutParams(int width, int height, float weight) {
super(width, height);
this.weight = weight;
} /**
* {@inheritDoc}
*/
public LayoutParams(ViewGroup.LayoutParams p) {
super(p);
} /**
* {@inheritDoc}
*/
public LayoutParams(ViewGroup.MarginLayoutParams source) {
super(source);
} /**
* Copy constructor. Clones the width, height, margin values, weight,
* and gravity of the source.
*
* @param source The layout params to copy from.
*/
public LayoutParams(LayoutParams source) {
super(source); this.weight = source.weight;
this.gravity = source.gravity;
} @Override
public String debug(String output) {
return output + "LinearLayout.LayoutParams={width=" + sizeToString(width) +
", height=" + sizeToString(height) + " weight=" + weight + "}";
}
}
很显然它继承自ViewGroup.MarginLayoutParams,而且添加了自己独有的几个 属性,比如weight、gravity,同时继承得到了width、height、margin等属性,所以,LinearLayout的子view就可以使用这些属性。
RelativeLayout.java
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
@ViewDebug.ExportedProperty(category = "layout", resolveId = true, indexMapping = {
@ViewDebug.IntToString(from = ABOVE, to = "above"),
@ViewDebug.IntToString(from = ALIGN_BASELINE, to = "alignBaseline"),
@ViewDebug.IntToString(from = ALIGN_BOTTOM, to = "alignBottom"),
@ViewDebug.IntToString(from = ALIGN_LEFT, to = "alignLeft"),
@ViewDebug.IntToString(from = ALIGN_PARENT_BOTTOM, to = "alignParentBottom"),
@ViewDebug.IntToString(from = ALIGN_PARENT_LEFT, to = "alignParentLeft"),
@ViewDebug.IntToString(from = ALIGN_PARENT_RIGHT, to = "alignParentRight"),
@ViewDebug.IntToString(from = ALIGN_PARENT_TOP, to = "alignParentTop"),
@ViewDebug.IntToString(from = ALIGN_RIGHT, to = "alignRight"),
@ViewDebug.IntToString(from = ALIGN_TOP, to = "alignTop"),
@ViewDebug.IntToString(from = BELOW, to = "below"),
@ViewDebug.IntToString(from = CENTER_HORIZONTAL, to = "centerHorizontal"),
@ViewDebug.IntToString(from = CENTER_IN_PARENT, to = "center"),
@ViewDebug.IntToString(from = CENTER_VERTICAL, to = "centerVertical"),
@ViewDebug.IntToString(from = LEFT_OF, to = "leftOf"),
@ViewDebug.IntToString(from = RIGHT_OF, to = "rightOf"),
@ViewDebug.IntToString(from = ALIGN_START, to = "alignStart"),
@ViewDebug.IntToString(from = ALIGN_END, to = "alignEnd"),
@ViewDebug.IntToString(from = ALIGN_PARENT_START, to = "alignParentStart"),
@ViewDebug.IntToString(from = ALIGN_PARENT_END, to = "alignParentEnd"),
@ViewDebug.IntToString(from = START_OF, to = "startOf"),
@ViewDebug.IntToString(from = END_OF, to = "endOf")
}, mapping = {
@ViewDebug.IntToString(from = TRUE, to = "true"),
@ViewDebug.IntToString(from = 0, to = "false/NO_ID")
}) private int[] mRules = new int[VERB_COUNT];
private int[] mInitialRules = new int[VERB_COUNT]; private int mLeft, mTop, mRight, mBottom; private int mStart = DEFAULT_MARGIN_RELATIVE;
private int mEnd = DEFAULT_MARGIN_RELATIVE; private boolean mRulesChanged = false;
private boolean mIsRtlCompatibilityMode = false; /**
* When true, uses the parent as the anchor if the anchor doesn't exist or if
* the anchor's visibility is GONE.
*/
@ViewDebug.ExportedProperty(category = "layout")
public boolean alignWithParent; public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs); TypedArray a = c.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.RelativeLayout_Layout); final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
mIsRtlCompatibilityMode = (targetSdkVersion < JELLY_BEAN_MR1 ||
!c.getApplicationInfo().hasRtlSupport()); final int[] rules = mRules;
//noinspection MismatchedReadAndWriteOfArray
final int[] initialRules = mInitialRules; final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignWithParentIfMissing:
alignWithParent = a.getBoolean(attr, false);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toLeftOf:
rules[LEFT_OF] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toRightOf:
rules[RIGHT_OF] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_above:
rules[ABOVE] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_below:
rules[BELOW] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignBaseline:
rules[ALIGN_BASELINE] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignLeft:
rules[ALIGN_LEFT] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignTop:
rules[ALIGN_TOP] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignRight:
rules[ALIGN_RIGHT] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignBottom:
rules[ALIGN_BOTTOM] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentLeft:
rules[ALIGN_PARENT_LEFT] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentTop:
rules[ALIGN_PARENT_TOP] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentRight:
rules[ALIGN_PARENT_RIGHT] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentBottom:
rules[ALIGN_PARENT_BOTTOM] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerInParent:
rules[CENTER_IN_PARENT] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerHorizontal:
rules[CENTER_HORIZONTAL] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_centerVertical:
rules[CENTER_VERTICAL] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toStartOf:
rules[START_OF] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_toEndOf:
rules[END_OF] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignStart:
rules[ALIGN_START] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignEnd:
rules[ALIGN_END] = a.getResourceId(attr, 0);
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentStart:
rules[ALIGN_PARENT_START] = a.getBoolean(attr, false) ? TRUE : 0;
break;
case com.android.internal.R.styleable.RelativeLayout_Layout_layout_alignParentEnd:
rules[ALIGN_PARENT_END] = a.getBoolean(attr, false) ? TRUE : 0;
break;
}
}
mRulesChanged = true;
System.arraycopy(rules, LEFT_OF, initialRules, LEFT_OF, VERB_COUNT); a.recycle();
}
这段代码没有贴完整,但是我们可以看到,它同样继承自ViewGroup.MarginLayoutParams,而且加入了大量独有的属性。
至此,我们对LayoutParams有了一个大致的概念,至于在我们自己继承ViewGroup时如何使用,应该根据自己的需要,要么继承自ViewGroup.LayoutParams,要么继承自ViewGroup.MaginLayoutParams,我在前面的demo中是这么简单实现的:
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
//Log.e(TAG, "generateLayoutParams attrs");
return new MarginLayoutParams(getContext(), attrs);
} @Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
//Log.e(TAG, "generateDefaultLayoutParams");
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
} @Override
protected boolean checkLayoutParams(LayoutParams p) {
return super.checkLayoutParams(p);
} @Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
//Log.e(TAG, "generateLayoutParams p");
return new MarginLayoutParams(p);
}
也就是说,我根本就没重写自己的LayoutParams。所以在generateLayoutParams(AttributeSet attrs)方法中,返回了ViewGroup.MarginLayoutParams对象,这个方法会被调用,但是什么时候调用,我们在接下来的文章中接着分析。
简单研究Android View绘制二 LayoutParams的更多相关文章
- 简单研究Android View绘制三 布局过程
2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...
- 简单研究Android View绘制一 测量过程
2015-07-27 16:52:58 一.如何通过继承ViewGroup来实现自定义View?首先得搞清楚Android时如何绘制View的,参考Android官方文档:How Android Dr ...
- 浅析Android View(二)
深入理解Android View(一) View的位置參数信息 二.View的绘制过程 View的绘制过程一共分为三个部分: - measure(測量View的大小) - layout(确定View的 ...
- Android View绘制流程
框架分析 在之前的下拉刷新中,小结过触屏消息先到WindowManagerService(Wms)然后顺次传递给ViewRoot(派生自Handler),经decor view到Activity再传递 ...
- Android View绘制13问13答
1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view? 答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程.draw ...
- android view : 绘制
说到绘制,其实就是如何把一个view的对象,变成手机上可视的图形.很多人总结3个过程:测量,布局,绘制.这也是所有的要显示图形的程序所应该抽象的3个步骤,测量就是测量出你view的大小,布局就是要显示 ...
- Android View绘制过程
Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...
- Android View 绘制过程
Android的View绘制是从根节点(Activity是DecorView)开始,他是一个自上而下的过程.View的绘制经历三个过程:Measure.Layout.Draw.基本流程如下图: per ...
- Android View 绘制刷新流程分析
Android中对View的更新有很多种方式,使用时要区分不同的应用场合.1.不使用多线程和双缓冲 这种情况最简单,一般只是希望在View发生改变时对UI进行重绘.你只需显式地调用View对 ...
随机推荐
- IUS tcl cmd
Incisive simulator中的command-line language基于TCL. Ncsim> command [-modifier] [-options] [arguments] ...
- configure.ac:32: error: possibly undefined macro: AC_DEFINE
在ubuntu 下编译snappy时,在检查依赖关系时,处理autoconf的包时,在相关依赖包都已经安装的情况下,报如下错误,死活不过. configure.ac:32: error: possib ...
- .net环境下ckeditor与ckfinder中文文件链接乱码的问题
.net环境下ckeditor与ckfinder中文文件链接乱码的问题 将ckfinder.js中的getUrl:function(){return this.folder.getUrl()+enco ...
- 提高Oracle的WHERE语句性能一些原则
索引是表的一个概念部分 , 用来提高检索数据的效率, ORACLE 使用了一个复杂的自平衡 B-tree 结构 . 通常 , 通过索引查询数据比全表扫描要快 . 当 ORACLE 找出执行查询和 Up ...
- 关于学习Knockoutjs--入门(一)
前段时间做项目一直在用knockout,虽然用着不怎么利索,但是知识是一点一点探索的. 首先介绍一下 Knockout是什么? 他是一个很优秀的js库,他最大的功能就是实现双向绑定,它可以帮助你仅使用 ...
- MVC异常日志生产者消费者模式记录(异常过滤器)
生产者消费者模式 定义自己的异常过滤器并注册 namespace Eco.Web.App.Models { public class MyExceptionAttribute : HandleErro ...
- python核心编程学习记录之模块
- NS_ENUM vs. NS_OPTIONS
NS_ENUM用于定义普通枚举值,NS_OPTIONS用于定义位移相关操作的枚举值: typedef NS_ENUM(NSUInteger, EOCConnectionState) { EOCConn ...
- hdu 5780 gcd
题意:给定$x, n$满足$1 \leq x, n \leq 1000000$,求$\sum{(x^a-1,x^b-1)}$对$1e9+7$取模后的值,其中$1 \leq a, b \leq n$. ...
- JS设置cookie
cookie 与 session 是网页开发中常用的信息存储方式.Cookie是在客户端开辟的一块可存储用户信息的地方:Session是在服务器内存中开辟的一块存储用户信息的地方. JavaScrip ...