自定义控件---view

简单绘制一个自定义控件,继承View,效果如下:
这里写图片描述

效果分析
共需绘制三个部分,圆环,内圆,字体。

要求:
1. 控件大小必须是正方形
2.用户使用wrap_contnet时,限制其大小固定
3. 圆占半径的1/3 圆环的宽度也占半径的1/3

知识点:
1. 首先在自定义控件中测量控件需要的宽高。
测量模式:
* EXACTLY:精确测量(布局中为固定值,或者match_parent时)。
* AT_MOST:AT_MOST模式是在布局中写入 wrap_content时的测量模式,该模式控件大小随内容改变,不超过父容器,此模式下返回的值是所允许的最大值。
* UNSPECIFIED:是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
2. 绘制各个部分。

  • paint
setTextSize(float textSize)  // 设置字体大小
setStyle(Style.FILL);//设置填充样式

这里写图片描述

  • canvas
 canvas.drawArc(rect, //弧线所使用的矩形区域大小    

            0,  //开始角度    

            90, //扫过的角度    

            false, //是否使用中心    

            paint);    
如果想绘制圆环,必须设置paint的style为:paint.setStyle(Paint.Style.STROKE);也就是只绘制边即可,
圆环的宽度通过设置画笔的setStrokeWidth(宽度)来设置。

自定义属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="circleView">
        <attr name="textSize" format="dimension"/>
        <attr name="text" format="string"/>
        <attr name="textColor" format="color"/>
        <attr name="circleColor" format="color"/>
        <attr name="arcColor" format="color"/>
        <!--起始角度-->
        <attr name="startAngle" format="integer"/>
        <!--扫描角度-->
        <attr name="sweepAngle" format="integer"/>
    </declare-styleable>
</resources>

建立一个circleView继承View,并实现View.OnClickListener接口使其可以点击

读取自定义属性
  public circleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint();
        paint.setAntiAlias(true);
        getAttrs(context, attrs);

    }

    private void getAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.circleView);
        try {
            circleColor = ta.getColor(R.styleable.circleView_circleColor, 0);
            arcColor = ta.getColor(R.styleable.circleView_arcColor, 0);
            textColor = ta.getColor(R.styleable.circleView_textColor, 0);
            textSize = ta.getDimension(R.styleable.circleView_textSize, 50);
            text = ta.getString(R.styleable.circleView_text);
            startAngle = ta.getInt(R.styleable.circleView_startAngle, 0);
            sweepAngle = ta.getInt(R.styleable.circleView_sweepAngle, 90);
        } catch (Exception e) {
            e.printStackTrace();
        }
        ta.recycle();
        this.setOnClickListener(this);
    }
测量:

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

        int width = getSize(widthMeasureSpec);
        int height = getSize(heightMeasureSpec);
        //初始化画布  正方形
        if (width < height) {
            bgWidth = width;
        } else {
            bgWidth = height;
        }
        //半径
        mMRadious = (int) (bgWidth * 1.0f / 2);

        //根据进度来设置绘制圆环的弧度
        sweepAngle = sweepAngle > 360 ? 360 : sweepAngle;
        //确定中心环的半径  (占据半径的1/3)
        mCircleRadious = (int) (mMRadious * 0.33f);
        //确定外边圆环的宽度 (占据半径的1/3)
        mStroke = (int) (mMRadious * 0.33f);
        //得到圆环宽度的一半,用来设置绘制圆环区域,
        mHalfStroke = mStroke / 2;
        setMeasuredDimension(bgWidth, bgWidth);
    }
    public int getSize(int measureSpec) {
        int result = defaultSize;
        int size = MeasureSpec.getSize(measureSpec);
        int mode = MeasureSpec.getMode(measureSpec);

        switch (mode) {
            case MeasureSpec.EXACTLY:
                result = size;
                break;
            case MeasureSpec.AT_MOST:
                //AT_MOST模式是在布局中写入 wrap_content时的测量模式:
                // 该模式控件大小随内容改变,不超过父容器,此模式下返回的值是所允许的最大值。
                result = Math.min(size, defaultSize);
                break;
            case MeasureSpec.UNSPECIFIED:
                result = defaultSize;
                break;
        }
        return result;
    }
绘制

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        paint.setStyle(Paint.Style.FILL);
        //将绘制中心转移到画布中心,方便绘制
        canvas.translate(bgWidth / 2, bgWidth / 2);
        //画里面的园
        paint.setColor(circleColor);
        canvas.drawCircle(0, 0, mCircleRadious, paint);
        //画进度文字
        //计算文字应该显示的百分比
        float s = sweepAngle * 1.0f / 360;
        paint.setColor(textColor);
        paint.setTextSize(textSize);
        int progress = (int) (s * 100);
        String drawText = progress + "%";
        //测量文字的宽度
        int textWidth = (int) paint.measureText(drawText);
        //得到文字的高度
        int textHeight = (int) (paint.descent() - paint.ascent());
        canvas.drawText(progress + "%", -textWidth / 2, textHeight / 3, paint);
        //画圆环
        paint.setColor(arcColor);
        //绘制圆环的区域,drawArc绘制圆弧时,圆弧的半径末点在圆环的宽度中心。
        RectF rectF = new RectF(-mMRadious + mHalfStroke, -mMRadious + mHalfStroke,
                mMRadious - mHalfStroke, mMRadious - mHalfStroke);
        paint.setStrokeWidth(mStroke);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawArc(rectF, startAngle, sweepAngle, false, paint);
        canvas.restore();
    }
点击之后模拟重绘
   Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            postInvalidate();
        }
    };
    @Override
    public void onClick(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 360; i++) {
                    SystemClock.sleep(20);
                    sweepAngle = i;
                    handler.sendEmptyMessage(0);
                }
            }
        }).start();
    }
在布局中引用该空间
 <ceo.yangqing.meimaobing.doubleservice.circleView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:background="#92f7eb"
        app:arcColor="#ed0a25"
        app:circleColor="#23e120"
        app:startAngle="0"
        app:sweepAngle="260"
        app:textColor="#060606"
        app:textSize="15dp"
        />
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值