android自定义View&自定义ViewGroup(下)

来源:互联网 发布:程序员什么时候跳槽好 编辑:程序博客网 时间:2024/05/20 23:34
接上篇,android自定义View&自定义ViewGroup(上)

上篇主要是自定义View,本篇来看看自定义ViewGroup。

先来复习一下一般自定义ViewGroup中需要复写的方法:


void onMeasure(int widthMeasureSpec, int heightMeasureSpec)void onSizeChanged(int w, int h, int oldw, int oldh)void onLayout(boolean changed, int left, int top, int right, int bottom)void onDraw(Canvas canvas)

:ViewGroup的onLayout方法是必须重写的,而onDraw方法默认是不会调用的,如果想执行onDraw方法,可以通过下面两种方法:
1.设置透明背景:
在构造函数中:setBackgroundColor(Color.TRANSPARENT);
或者在xml中:android:background="@color/transparent"
2.或者可以在构造函数中添加setWillNotDraw(false);
自定义ViewGroup中如果需要获得自定义属性,方法和上篇自定义View中获取方法是一样的,请参照上篇。

ViewGroup常用重写方法:

  • onMeasure
    measureChildren方法触发所有子View的onMeasure方法测量自己并把测量结果回传给ViewGroup(ViewGroup传递给子View建议宽高和测量模式,如果子View的宽高是wrap_content,那么只有子View测量出自己的宽和高),当所有子View测量完毕后,再调用setMeasuredDimension将ViewGroup自身的宽和高传给它的父View。
  • onSizeChanged
    在onMeasure()后执行,只有大小发生了变化才会执行onSizeChange
  • onLayout
    排列所有子View的位置
    通过getChildCount()获取所有子view,getChildAt获取childview调用各自的layout(int, int, int, int)方法来排列自己。
  • onDraw
    上面已经提到,自定义ViewGroup默认不会触发onDraw方法,需要设置背景色或者setWillNotDraw(false)来手动触发。

自定义ViewGroup例子,先上图:



代码已上传到github:自定义ViewGroup(五环图)

思路:首先是5个自定义圆环,在自定义ViewGroup的onLayout中排列他们,在onDraw中写文字。
核心代码:

public class CustomFiveRings extends ViewGroup {    private Context mContext;    private TextPaint mPaint;    private int startX;//圆环起始X轴    private int startY;//圆环起始Y轴    private int mWidth;//ViewGroup的宽    private int mHeight;//ViewGroup的高    public CustomFiveRings(Context context) {        this(context, null);    }    public CustomFiveRings(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public CustomFiveRings(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        setBackgroundColor(Color.TRANSPARENT);        mContext = context;        mPaint = new TextPaint();        mPaint.setAntiAlias(true);        mPaint.setDither(true);        mPaint.setTextSize(50);        mPaint.setColor(Color.BLACK);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //触发所有子View的onMeasure函数去测量宽高        measureChildren(widthMeasureSpec, heightMeasureSpec);        //MeasureSpec封装了父View传递给子View的布局要求        int wMode = MeasureSpec.getMode(widthMeasureSpec);        int wSize = MeasureSpec.getSize(widthMeasureSpec);        int hMode = MeasureSpec.getMode(heightMeasureSpec);        int hSize = MeasureSpec.getSize(heightMeasureSpec);        switch (wMode) {            case MeasureSpec.EXACTLY:                mWidth = wSize;                break;            case MeasureSpec.AT_MOST:                //这里应该先计算所有子view的宽度,暂时先写死                mWidth = wSize;                break;            case MeasureSpec.UNSPECIFIED:                break;        }        switch (hMode) {            case MeasureSpec.EXACTLY:                mHeight = hSize;                break;            case MeasureSpec.AT_MOST:                //这里应该先计算所有子view的高度,暂时先写死                mHeight = hSize;                // mHeight = getCircleHeight() / 2 * 3;                break;            case MeasureSpec.UNSPECIFIED:                break;        }        setMeasuredDimension(mWidth, mHeight);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int childNum = getChildCount();        startX = startY = 0;        int gap = 10;//同一行圆圈之间的间隔        int screenWidth = DpUtil.getScreenSizeWidth(mContext);        int firstTotalWidth = 0;//第一行子View的总宽度        int secondTotalWidth = 0;//第二行子View的总宽度        for (int i = 0; i < childNum; i++) {            View childView = getChildAt(i);            int childWidth = childView.getMeasuredWidth();            if (i <= 2) {                //前三个总宽度                firstTotalWidth += childWidth;            } else {                //后两个总宽度                secondTotalWidth += childWidth;            }        }        int leftFMargin = (screenWidth - firstTotalWidth - gap * 2) / 2;        int leftSMargin = (screenWidth - secondTotalWidth - gap) / 2;        for (int i = 0; i < childNum; i++) {            View childView = getChildAt(i);            int childWidth = childView.getMeasuredWidth();            int childHeight = childView.getMeasuredHeight();            if (i <= 2) {                //排列前三个圆圈                if (i == 0) {                    childView.layout(leftFMargin + startX, startY, leftFMargin + startX + childWidth, startY + childHeight);                    startX += childWidth;                } else {                    childView.layout(leftFMargin + startX + gap, startY, leftFMargin + startX + gap + childWidth, startY + childHeight);                    startX += (childWidth + gap);                }                if (i == 2) {                    startX = 0;                    startY += childHeight / 2;                }            } else {                //排列后两个圆圈                if (i == 3) {                    childView.layout(leftSMargin + startX, startY, leftSMargin + startX + childWidth, startY + childHeight);                    startX += childWidth;                } else {                    childView.layout(leftSMargin + startX + gap, startY, leftSMargin + startX + gap + childWidth, startY + childHeight);                    startX += (childWidth + gap);                }            }        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        int screenWidth = DpUtil.getScreenSizeWidth(mContext);        String upStr = "同一个世界,同一个梦想";        String downStr = "One World,One Dream";        canvas.drawText(upStr, (screenWidth - mPaint.measureText(upStr)) / 2, getCircleHeight() / 2 * 3 + 60, mPaint);        canvas.drawText(downStr, (screenWidth - mPaint.measureText(downStr)) / 2, getCircleHeight() / 2 * 3 + 120, mPaint);    }    /**     * 获得圆环高度     *     * @return 圆环高度     */    private int getCircleHeight() {        //5个圆环大小是一样的,这里就直接取第一个了        View childView = getChildAt(0);        return childView.getMeasuredHeight();    }}



0 0