自定义ViewGroup之仿奥运五环的实现

图片预览
这里写图片描述

1. 分析和实现原理

1. 自定义一个圆环
2. 自定义ViewGroup,然后添加圆环
3. onMeasue和onLayout处理
4. 绘制文字

2. 绘制圆环

//平移坐标系到中心点
canvas.translate(mCenterX,mCenterY);
mPaint.setColor(mRingColor);
//两种思路 画圆 或者画圆环
canvas.drawCircle(0,0,mRingRadius,mPaint);

//或者画圆环
//        float left = -mRingRadius;
//        float top = -mRingRadius;
//        float right = mRingRadius;
//        float bottom = mRingRadius;
//        mRectF.set(left,top,right,bottom);
//        canvas.drawArc(mRectF,0,360,false,mPaint);

3. ViewGroup中添加圆环


int margin = dp2px(8);
//添加5个圆环
for (int i = 0; i < 5; i++) {
    MarginLayoutParams lp = new MarginLayoutParams(
            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    lp.setMargins(margin, margin, 0, margin);
    addView(new RingProgressBar(context, attrs),lp);
}

4. onMeasure处理

这个代码都很简单 没什么解释的


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    //wrap_content计算宽高
    int width = 0;
    int height = 0;

    //计算上面 下面的宽高
    int tWidth = 0;
    int bWidth = 0;
    int tHeight = 0;
    int bHeight = 0;
    for (int i = 0; i < getChildCount(); i++) {

        View child = getChildAt(i);
        //测量每一个子孩子的宽高
        measureChild(child,widthMeasureSpec,heightMeasureSpec);

        MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
        int cWidth = child.getMeasuredWidth() + lp.leftMargin;
        int cHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

        if(i < 3){
            tWidth += cWidth;
            tHeight = cHeight;
        }else{
            bWidth += cWidth;
            bHeight = tHeight / 2 + cHeight;
        }
    }

    mRingMaxHeight = Math.max(tHeight,bHeight);
    width = Math.max(tWidth,bWidth);
    //要加上文字的高度和上下间距
    height = Math.max(tHeight,bHeight) + mENDescHeight + mCNDescHeight+ textSpacing * 2;

    //wrap_content 取子View测量的宽高
    int measureWidth = widthMode == MeasureSpec.AT_MOST ? width : widthSize;
    int measureHeight  = heightMode == MeasureSpec.AT_MOST ? height : heightSize;

    setMeasuredDimension(measureWidth,measureHeight);
}

5. onLayout处理

计算每一个圆环左上右下的值,完成布局,完成放置子View的位置


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

   //上面下面子view距离左边的间距
   int tLeft = 0;
   int bLeft = 0;
   int top = 0;
   for (int i = 0; i < getChildCount(); i++) {

       View child = getChildAt(i);
       //如果子View是GONE,则不处理
       if(child.getVisibility() == View.GONE){
           continue;
       }

       MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
       int cWidth = child.getMeasuredWidth();
       int cHeight = child.getMeasuredHeight();

      //上面三个圆环 top都是一样的。
      //left值等于前一个圆环的宽度加上左边的margin值
       if(i < 3){

           if(i == 0){
               tLeft = lp.leftMargin;
           }else {
               tLeft = tLeft + cWidth + lp.leftMargin;
           }
           top = lp.topMargin;
           child.layout(tLeft, top, tLeft + cWidth, top + cHeight);

       }else {
       //下面两个圆环top的高度等于topMargin+上面圆环高度的1/2,左边的left第一个圆环等于
       // 上面圆环的宽度取它的0.55倍+距离左边的间距,第二个圆环等于下面
       // 第一个圆环的left+圆环宽度+leftMargin
           if( i == 3){
               bLeft = (int) (0.55f * cWidth + lp.leftMargin);
           }else{
               bLeft = bLeft + cWidth + lp.leftMargin;
           }
           top = (int) (lp.topMargin + 0.5 * cHeight);
           child.layout(bLeft,top,bLeft + cWidth,top + cHeight);

       }
   }
}

6. 绘制文字

绘制文字的时候文字的top值=上面圆环的高度+文字之间的间距


@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    //画文字
    float cnY = mRingMaxHeight + textSpacing;
    float enY = cnY + mCNDescHeight+ textSpacing;
    canvas.drawText(chineseDesc,mCenterX,cnY,mPaint);
    canvas.drawText(englishDesc,mCenterX, enY,mPaint);
}

7. 小结和源码下载

小结:
最核心还是onMeasure和onlayout的处理

源码下载:
最后统一提供代码下载地址    

8.联系方式

QQ:1509815887
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值