当我们继承自 ViewGroup
后,需要重写 onMeasure()
方法来计算并设置该布局的子 View 布局参数,在该方法中,会通过 MeasureSpec
来获取父布局传递的测量模式和大小值,我们需要根据这些值来确定子 View 的大小和位置。
下面是重写 onMeasure()
方法的步骤:
1.实现该方法
我们需要在子类中重写该方法并在其中编写测量布局的代码。例如下面这个示例中:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 根据传递过来的测量模式和大小值计算子 View 的大小和位置
// ...
super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 调用父类方法保存测量大小
}
2.测量子 View 大小和位置
我们需要在该方法内根据测量模式和大小值计算并设置子 View 的大小和位置。测量子 View 的大小和位置可以通过 MeasureSpec
的静态方法进行,分 3 种:
MeasureSpec.EXACTLY
:如果指定该模式,则子 View 的大小将完全按照指定大小进行测量。MeasureSpec.AT_MOST
:如果指定该模式,则子 View 的大小不能超过指定大小,否则会进行缩放。MeasureSpec.UNSPECIFIED
:如果指定该模式,则子 View 大小没有限制。
3.设置子 View 的布局参数
在计算子 View 的大小和位置之后,我们需要设置他们的布局参数以便进行布局,需要使用 ViewGroup.LayoutParams
构造方法创建一个 LayoutParams
对象,并设置参数值,例如:
childView.setLayoutParams(new LayoutParams(width, height));
下面是一个完整的例子,它是一个简单的自定义 ViewGroup,它包含了两个子 View,并将其排列在一行中:
public class MyViewGroup extends ViewGroup {
// 子 View 的宽和高
private int childWidth = 200;
private int childHeight = 50;
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
int height = 0;
int count = getChildCount();
// 测量所有子 View 的最大宽度和高度
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
width += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
height = Math.max(height, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
}
// 使用测量得到的最大宽度和高度,设置自身 View 的布局参数
setMeasuredDimension(resolveSize(width, widthMeasureSpec),
resolveSize(height, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 将子 View 竖向排列
int count = getChildCount();
int left = 0;
int top = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
left += lp.leftMargin;
top += lp.topMargin;
child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
}
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
@Override
protected LayoutParams generateLayoutParams(LayoutParams p) {
return new LayoutParams(p);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected boolean checkLayoutParams(LayoutParams p) {
return p instanceof LayoutParams;
}
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
public LayoutParams(LayoutParams source) {
super(source);
}
}
}
在上面的例子中,我们通过继承 ViewGroup
并实现 onMeasure()
和 onLayout()
方法,来计算并布局子 View。在 onMeasure()
方法中,我们测量了子 View 的最大宽度和高度,然后将计算结果设置为自身 View 的布局参数,最后在 onLayout()
方法中将子 View 水平排列。我们还重写了其他几个方法以便支持 ViewGroup 参数。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:解析:继承ViewGroup后的子类如何重写onMeasure方法 - Python技术站