菜鸟记录一下,把之前的笔记抄到这里
/**
* A layout that lets you specify exact locations (x/y coordinates) of its
* children. Absolute layouts are less flexible and harder to maintain than
* other types of layouts without absolute positioning.
*
* XML attributes
See {@link
* android.R.styleable#ViewGroup ViewGroup Attributes}, {@link
* android.R.styleable#View View Attributes}
*
* @deprecated Use {@link android.widget.FrameLayout}, {@link android.widget.RelativeLayout}
* or a custom layout instead.
*/
@Deprecated
@RemoteView
public class AbsoluteLayout extends ViewGroup {
1、哈哈,首先,AbsoluteLayout 继承自 ViewGroup;
2、同样,AbsoluteLayout 需要通过onMeasure 和 onLayout:
a、首先,需要通过 attrs 获取 AbsoluteLayout 的自定义属性,不难理解;
/**
* 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:
*
*
* layout_x
: the X location of the child
* layout_y
: the Y location of the child
* - All the XML attributes from
* {@link android.view.ViewGroup.LayoutParams}
*
*
* @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) {
super(c, attrs);
TypedArray a = c.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.AbsoluteLayout_Layout);
x = a.getDimensionPixelOffset(
com.android.internal.R.styleable.AbsoluteLayout_Layout_layout_x, 0);
y = a.getDimensionPixelOffset(
com.android.internal.R.styleable.AbsoluteLayout_Layout_layout_y, 0);
a.recycle();
}
b、onMeasure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
// Find out how big everyone wants to be
measureChildren(widthMeasureSpec, heightMeasureSpec);
// Find rightmost and bottom-most child
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
int childRight;
int childBottom;
AbsoluteLayout.LayoutParams lp
= (AbsoluteLayout.LayoutParams) child.getLayoutParams();
childRight = lp.x + child.getMeasuredWidth();
childBottom = lp.y + child.getMeasuredHeight();
maxWidth = Math.max(maxWidth, childRight);
maxHeight = Math.max(maxHeight, childBottom);
}
}
// Account for padding too
maxWidth += mPaddingLeft + mPaddingRight;
maxHeight += mPaddingTop + mPaddingBottom;
// Check against minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
}
1)首先,通过 getChildCount() 获取 子控件的个数;
2)由注释 Find out how big everyone wants to be 可知,第二步通过measureChildren(widthMeasureSpec, heightMeasureSpec);
对子控件进行测量;
3)接下来进入了一个 for 循环,通过注释 // Find rightmost and bottom-most child
可知,需要找出最右边和最下边的子控件,如下
从左上角开始,使用 wrap_content,通过上图可以知道,需要找出 最右边 和 最下边的 子view的 right 或者 bottom,所以接下来 for 循环中 便是 通过 每次获取 以及 比较来找到想要的结果:
1)首先,获取每个 子view,同样,当 child.getVisibility() 为 GONE 的时候,我们可以直接忽略,所以判断条件为 不是 GONE;
2)通过 AbsoluteLayout.LayoutParams 获取每个子view的 layoutParams,layoutParams 封装了view 的 x 以及 y
public static class LayoutParams extends ViewGroup.LayoutParams {
/**
* The horizontal, or X, location of the child within the view group.
*/
public int x;
/**
* The vertical, or Y, location of the child within the view group.
*/
public int y;
上面是 AbsoluteLayout 的 LayoutParams ,对比一下 RelativeLayout 的 LayoutParams,
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"),
通过对比可知,AbsoluteLayout 的 LayoutParams 直接继承了 ViewGroup 的 LayoutParams ,而 RelativeLayout 的 继承的 是 MarginLayoutParams,可以得知 AbsoluteLayout 不支持 margin 属性,所以 在 onmeasure 的 for 循环中对每个子View 进行测量无需考虑 margin;
3)接下来,通过 每个 子View 的 x 以及 y 坐标,以及子View 宽高,获得最大的 height 和 width
childRight = lp.x + child.getMeasuredWidth();
childBottom = lp.y + child.getMeasuredHeight();
maxWidth = Math.max(maxWidth, childRight);
maxHeight = Math.max(maxHeight, childBottom);
4)for 循环之后,执行以下代码:
// Account for padding too
maxWidth += mPaddingLeft + mPaddingRight;
maxHeight += mPaddingTop + mPaddingBottom;
// Check against minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
主要是通过 for 循环计算得出的最大的 height 以及 width,并且加上 最外层 AbsoluteLayout 的 padding,如下:
AbsoluteLayout 添加了 mPaddingLeft 和 mPaddingBottom 之后,子View的坐标轴会 向右 移动 mPaddingLeft 以及向下移动 mPaddingBottom,所以 for 循环之后需要 加上 这两个参数;
c、onLayout
onLayout 代码如下:
@Override
protected void onLayout(boolean changed, int l, int t,
int r, int b) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
AbsoluteLayout.LayoutParams lp =
(AbsoluteLayout.LayoutParams) child.getLayoutParams();
int childLeft = mPaddingLeft + lp.x;
int childTop = mPaddingTop + lp.y;
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(),
childTop + child.getMeasuredHeight());
}
}
}
同样,通过 getChildCount() 获取数目之后,在for循环中摆放 子View的位置,AbsoluteLayout 通过 x和 y 来确定 位置,所以 通过 x、y 以及 子view 的height 以及 width 即可,调用 child.layout();四个参数分别为 子view 的 x、子view 的y、子view 的 width、子view 的height;
3、接下来,有一个方法
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs)
{
return new AbsoluteLayout.LayoutParams(getContext(), attrs);
}`
我们首先在 类 LayoutInflater 中可以看到如下代码:
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
可以知道,generateLayoutParams 方法将我们自定义 的属性转换成 父布局的 LayoutParams,所以我们在 xml 中使用属性也是通过这个方法转换。
以上便是个人对 AbsoluteLayout 的一点理解,不对之处欢迎吐槽。