继承ViewGroup自定义View
前奏
这段时间研究了下自定义view相关的知识,重写onMeasue,onLayout,onDraw这几个方法,大家估计都说的上来,但是,什么时候重写哪个方法,其实不见得每个Android开发都能说的上来。
自定义view应该有差不多四种情况:
1,继承View,重写onMeasure,onDraw,或者重写其中一个来达到自己的目的;
2,继承某个控件,重写其中的某个方法,达到自己的目的;
3,继承ViewGroup,重写onMeasure(有必要重写,因为通他是View中的实现,在ViewGroup中没有实现),onLayout(必须重写,因为是个抽象方法),onDraw(根据自己的需求来是否重写);
4,继承某个ViewGroup,重写某个方法来达到自己的目的;
在这篇文章中重点实现一个类似LinearLayout中横向排列的ViewGroup,重点讲一下第三个的自定义实现;
过程
第一步:新建个java类继承ViewGroup
public class CustomViewGroup extends ViewGroup {
public CustomViewGroup(Context context) {
super(context);
}
public CustomViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}}
第二步,重写onMeare
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;//viewGroup的宽度
int height = 0;//viewGroup的高度
//计算每个子view的长宽
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
//调用计算子View的宽高,传入的参数主要是父View对子View的限制
measureChild(view, widthMeasureSpec, heightMeasureSpec);
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
//这里把margin计算进来,要不然子View设置margin不起作用
width = width + childWidth + params.leftMargin + params.rightMargin;
//取最高的那个View的高度
height = Math.max(height, (childHeight + params.topMargin + params.bottomMargin));
}
//把计算出来的宽高保存起来
setMeasuredDimension(width, height);
}
第三步 重写onLayout
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childcount = getChildCount();
int leftPadding = getPaddingLeft();
int rightPadding = getPaddingRight();
int topPadding = getPaddingTop();
int bottomPadding = getPaddingBottom();
int width = leftPadding;
int top = topPadding;
//摆放每个子view
for (int i = 0; i < childcount; i++) {
View view = getChildAt(i);
int viewWidth = view.getMeasuredWidth();
int viewHeight = view.getMeasuredHeight();
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
int lv = width + params.leftMargin;
int tv = top + params.topMargin;
int rv = lv + viewWidth;
int bv = tv + viewHeight;
//注意调用的是view.layout方法,layout方法会去调onlayout,把计算出来的左上右下传进去
view.layout(lv, tv, rv, bv);
width = width + viewWidth + params.leftMargin + params.rightMargin;
}
}
最后说一点,如果复制上边的代码,会报错 ,因为MarginLayoutParams是不能被转化的,可以重写一下方法:
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateLayoutParams(LayoutParams p) {
return new MarginLayoutParams(p);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
以上一个简单的ViewGroup完成,主要带大家熟悉下onMeare,onLayout的过程,今天先到这里,后期计划加入滑动的功能,敬请期待~~