1.布局方式
垂直方向从下向上,水平方向采用流式布局
2.实现源码
public class VerticalView extends ViewGroup {
public VerticalView(Context context) {
super(context);
}
public VerticalView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new MarginLayoutParams(super.generateDefaultLayoutParams());
}
@Override
protected LayoutParams generateLayoutParams(LayoutParams p) {
if (p instanceof MarginLayoutParams)
return p;
else
return new MarginLayoutParams(p);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
int height = 0, width = 0;
int maxChildHeight = 0;
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int childCount = getChildCount();
View childView;
int rowWidth = 0;
if (heightMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.AT_MOST) {
for (int i = 0; i < childCount; i++) {
childView = getChildAt(i);
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();
int childHeight = childView.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin;
int childWidth = childView.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;
if (rowWidth + childWidth > parentWidth) {
width = Math.max(width, Math.max(rowWidth, childWidth));
height += maxChildHeight;
maxChildHeight = childHeight;
rowWidth = childWidth;
} else {
rowWidth += childWidth;
maxChildHeight = Math.max(maxChildHeight, childHeight);
}
}
height += maxChildHeight;
width = (width == 0) ? rowWidth : width;
setMeasuredDimension(width, height);
} else {
measureChildren(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(parentWidth, parentHeight);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int parentWidth = getWidth();
int childCount = getChildCount();
int lineWidth = 0;
b-=t;
int bottomHeight = b;
int lineHeight = 0;
View childView;
for (int i = 0; i < childCount; i++) {
childView = getChildAt(i);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();
if (i == 0) {
l = marginLayoutParams.leftMargin;
b = b - marginLayoutParams.bottomMargin ;
t = b - childView.getMeasuredHeight();
r = l + childView.getMeasuredWidth();
lineWidth = r + marginLayoutParams.rightMargin;
lineHeight = t - marginLayoutParams.topMargin;
} else {
if (lineWidth + marginLayoutParams.leftMargin + childView.getMeasuredWidth() + marginLayoutParams.rightMargin > parentWidth) {
l = marginLayoutParams.leftMargin;
b = lineHeight - marginLayoutParams.bottomMargin;
r = l + childView.getMeasuredWidth();
t = b - childView.getMeasuredHeight();
bottomHeight = lineHeight;
lineHeight = t - marginLayoutParams.topMargin;
lineWidth = r + marginLayoutParams.rightMargin;
} else {
l = lineWidth + marginLayoutParams.leftMargin;
b = bottomHeight - marginLayoutParams.bottomMargin;
r = l + childView.getMeasuredWidth();
t = b - childView.getMeasuredHeight();
lineHeight = Math.min(lineHeight, t - marginLayoutParams.topMargin);
lineWidth=r+marginLayoutParams.rightMargin;
}
}
childView.layout(l, t, r, b);
}
}
}
在measure方法中通过判断MeasureMode来决定是否计算子控件的宽度和高度,在layout方法中通过父布局的位置参数决定其包含的子控件的位置。
使用方法
<com.lc.VerticalView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="200dp"
android:background="#00ff00"
android:layout_height="50dp"/>
</com.lc.VerticalView>
该布局使用时,layout_width必须设置为“match_parent",否则layout_width设置为"match_parent"并且没有其他布局包含的控件可能宽度并不能占满屏幕。