需求是:进一步学习自定义控件,为子视图添加自定义属性
1. 在attr中添加自定义属性
<declare-styleable name= "CascadeLayout_LayoutParams">
<attr name ="layout_vertical_spacing" format= "dimension" />
</declare-styleable>
这里的属性名是 layout_vertical_spacing,因为该属性名前缀是layout_,同时又不是view的固有属性,所以该属性会被添加到layoutparams的属性表中。
2. 在自定义的layoutparams中获取该属性
public static class LayoutParams extends ViewGroup.LayoutParams {
int x;
int y;
int verticalSpacing;
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable. CascadeLayout_LayoutParams);
try {
verticalSpacing = a
.getDimensionPixelSize(
R.styleable. CascadeLayout_LayoutParams_layout_vertical_spacing ,
-1);
} finally {
a.recycle();
}
}
public LayoutParams( int w, int h) {
super(w, h);
}
}
3. 在view的布局文件中,添加该属性
<qingfengmy.cascadelayout.CascadeLayout
android:layout_width= "match_parent"
android:layout_height= "match_parent"
cascade:horizontal_spacing= "30dp"
cascade:vertical_spacing= "20dp" >
<View
android:layout_width= "100dp"
android:layout_height= "150dp"
cascade:layout_vertical_spacing="90dp" 这里添加了子视图的属性
android:background= "#FF0000" />
<View
android:layout_width= "100dp"
android:layout_height= "150dp"
android:background= "#00FF00" />
<View
android:layout_width= "100dp"
android:layout_height= "150dp"
android:background= "#0000FF" />
</qingfengmy.cascadelayout.CascadeLayout>
4. onmeasure的小修改
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
int height = getPaddingTop();
int verticalSpacing;
int count = getChildCount();
for (int i = 0; i < count; i++) {
verticalSpacing = mVerticalSpacing;
View child = getChildAt(i);
// 令每个子view测量自身
measureChild(child, widthMeasureSpec, heightMeasureSpec);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
width = getPaddingLeft() + mHorizontalSpacing * i;
// layoutParams中保存每个子视图左上角的x和y坐标
lp. x = width;
lp. y = height;
if (lp. verticalSpacing >= 0) {
verticalSpacing = lp. verticalSpacing;
}
width += child.getMeasuredWidth();
height += verticalSpacing;
}
// 使用计算所得的宽高设置整个布局的测量尺寸
width += getPaddingRight();
height += getChildAt(getChildCount() - 1).getMeasuredHeight()
+ getPaddingBottom();
// resolveSize的主要作用就是根据你提供的大小和MeasureSpec,返回你想要的大小值,这个里面根据传入模式的不同来做相应的处理
setMeasuredDimension(resolveSize(width, widthMeasureSpec),
resolveSize(height, heightMeasureSpec));
}
5.源码
https://github.com/qingfengmy/Cascadelayout