一、ViewGroup
(1)常用方法
- CustomViewGroup(Context context):在Java代码中new时调用
- CustomViewGroup(Context context, AttributeSet attrs):在xml布局文件中使用时自动调用
- generateLayoutParams(AttributeSet attrs):设置ViewGroup关联字View的属性
- onMeasure(int widthMeasureSpec, int heightMeasureSpec):计算子View宽高以及设置自己的宽高
- onLayout(boolean changed, int l, int t, int r, int b):设置子View的布局的位置
- onTouchEvent(MotionEvent event):监听触摸事件
(2)自定义属性
- 在values/attrs.xml自定义属性名称和取值类型
<resources>
<declare-styleable name="customViewGroup">
<attr name="horizontal_space" format="dimension"></attr>
<attr name="vertical_space" format="dimension"></attr>
</declare-styleable>
</resources>
- 在构造方法中获得自定义属性的值
(3)onMeasure与onLayout
- onMeasure测量计算子View宽高以及设置自己的宽高
EXACTLY:精确模式
AT_MOST:至多不超过模式
UNSPECIFIED:不确定模式
measureChildren:对所有的子View进行测量
measureChild:对单个View进行测量 - onLayout设置子View的大小与位置
getChildCount:获取子View的个数
getChildAt:获取单个子View
(4)自定义ViewGroup实现
- 重写onMeasure方法确定CustomViewGroup大小
- 重写generateLayoutParams方法设置LayoutParams为MarginLayoutParams
- 重写onLayout方法循环遍历子View
public class CustomViewGroup extends ViewGroup {
public CustomViewGroup(Context context) {
super(context);
}
public CustomViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//判断当前设置是否是wrap_content
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
int groupWidth = getMaxWidth();
int groupHeight = getTotalHeight();
setMeasuredDimension(groupWidth, groupHeight);
} else if (widthMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(getMaxWidth(), heightSize);
} else if (heightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSize, getTotalHeight());
}
}
private int getMaxWidth() {
int count = getChildCount();
int maxWidth = 0;
for (int i = 0; i < count; i++) {
int currentWidth = getChildAt(i).getMeasuredWidth();
if (maxWidth < currentWidth)
maxWidth = currentWidth;
}
return maxWidth;
}
private int getTotalHeight() {
int count = getChildCount();
int totalHeight = 0;
for (int i = 0; i < count; i++) {
totalHeight += getChildAt(i).getMeasuredHeight();
}
return totalHeight;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
int currentHeight = 0;
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
int height = view.getMeasuredHeight();
int width = view.getMeasuredWidth();
view.layout(l, currentHeight, l + width, currentHeight + height);
currentHeight += height;
}
}
}
(5)自定义ViewGroup自动换行
- 在CustomViewGroup构造方法中自定义属性
- 在onMeasure方法中测量ViewGroup控件的宽高
- 在onLayout方法中确定子View的位置
public class CustomViewGroup extends ViewGroup {
private int count;
//子View上方距离
private int marginTop;
//子View左侧距离
private int marginLeft;
//子View中上下的空闲区域
private int paddingTop;
//子View中左右的空闲区域
private int paddingLeft;
public CustomViewGroup(Context context) {
this(context, null);
}
public CustomViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@SuppressLint("CustomViewStyleable")
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customViewGroup);
marginTop = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_margin_top, 0);
marginLeft = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_margin_left, 0);
paddingTop = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_padding_top, 0);
paddingLeft = typedArray.getDimensionPixelOffset(R.styleable.customViewGroup_vg_padding_left, 0);
typedArray.recycle();
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int rowNumber = 1;
int totalWidth = 0;
int totalHeight = 0;
count = getChildCount();
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
view.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
totalWidth += (width + marginLeft);
if (totalWidth > widthSize) {
totalWidth = (width + marginLeft);
rowNumber++;
}
totalHeight = rowNumber * (height + marginTop);
}
setMeasuredDimension(widthSize, totalHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int rowNumber = 1;
int totalWidth = 0;
int totalHeight;
int actualWidth = r - l;
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
int width = getChildAt(i).getMeasuredWidth();
int height = getChildAt(i).getMeasuredHeight();
totalWidth += (width + marginLeft);
if (totalWidth > actualWidth) {
totalWidth = (width + marginLeft);
rowNumber++;
}
totalHeight = rowNumber * (height + marginTop);
view.layout(totalWidth - width, totalHeight - height, totalWidth, totalHeight);
}
}
}
网友评论