自定义圆环

自定义圆环继承view也可以完成,不过我这里选择继承sufaceview,sufaceview 通常用于频繁的view绘制,比如股票市场动态的折线图,对于这种高频操作,sufaceview要比view来的更合适一些。

sufaceview特性:可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。

老罗关于sufaceview的原理分析:http://blog.youkuaiyun.com/luoshengyang/article/details/8661317/

先贴上效果图:

代码如下:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * 进度圆环
 */
public class RingView extends SurfaceView implements SurfaceHolder.Callback{
    /** 画笔*/
    private Paint paint;
    /** 是否绘制*/
    private boolean isDraw;
    /** 绘图线程*/
    private MyThread myThread;
    /** 画布宽*/
    private int ringwidth;
    /** 画布高*/
    private int ringheight;
    private RectF rectF;
    private SurfaceHolder surfaceHolder;
    /** 画布*/
    private Canvas canvas;
    /** 目标进度 默认为80 */
    private int targetvalue=80;
    /** 当前进度*/
    private int nowvalue=0;
    /** 绘制进度文字*/
    private String text;
    /** 包裹文字的矩形*/
    private Rect rect;
    /**文字的高度 */
    private int textheight;
    /**
     * 设置目标进度 (0-100)
     * @param targetvalue
     */
    public void SetPlan(int targetvalue){
        if(targetvalue!=0)
            this.targetvalue=targetvalue;
    }
    public RingView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }
    public RingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public RingView(Context context) {
        super(context);
        init();
    }
    private void init() {
        //添加回调接口
        surfaceHolder=getHolder();
        surfaceHolder.addCallback(this);
        //初始化线程
        myThread=new MyThread();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ringwidth=measure(widthMeasureSpec,true);
        ringheight=measure(heightMeasureSpec,false);
        setMeasuredDimension(ringwidth,ringheight);
    }
    @SuppressWarnings("unused")
    private int measure(int MeasureSpecSize, boolean b) {
        int result=200;//设定一个值
        int size=MeasureSpec.getSize(MeasureSpecSize);
        int mode=MeasureSpec.getMode(MeasureSpecSize);
        if(mode==MeasureSpec.EXACTLY){
            result=size;
        }else if(mode==MeasureSpec.AT_MOST){
            if(true){//宽
                result=Math.max(size,result);
            }else{//高
                result=Math.min(size,result);
            }
        }
        return result;
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        ringwidth=w;
        ringheight=h;
    }
    //在创建时激发,一般在这里调用画图的线程。
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isDraw=true;
        paint=new Paint();
        paint.setStyle(Style.STROKE);
        paint.setTextSize(60);
        paint.setTextAlign(Paint.Align.CENTER);//设置了该属性  文字横向居中,但是纵向不会居中
        //开启线程
        myThread.start();
    }
    //在surface的大小发生改变时激发
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }
    //销毁时激发,一般在这里将画图的线程停止、释放。
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isDraw=false;
    }
    class MyThread extends Thread{
        @Override
        public void run() {
            if(isDraw){
                drawRing();
            }
        }
    }
    /**
     * 绘制圆环
     */
    public void drawRing() {
        int radius=Math.min(ringheight/2, ringwidth/2);
        rectF=new RectF(ringwidth/2-radius, ringheight/2-radius, ringwidth/2+radius, ringheight/2+radius);
        while(nowvalue<targetvalue){
            if(!isDraw)
                break;
            nowvalue+=1;
            text=nowvalue+" %";
            //锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了
            canvas=surfaceHolder.lockCanvas();
            canvas.drawColor(Color.WHITE);
            paint.setColor(Color.GREEN);
            canvas.drawArc(rectF, 0, 360, false, paint);
            paint.setColor(Color.RED);
            canvas.drawArc(rectF, 0,(float) (nowvalue*3.6), false, paint);
            MeasureText();
            canvas.drawText(text,ringwidth/2, ringheight/2+textheight/2, paint);
            //解除锁定并显示
            surfaceHolder.unlockCanvasAndPost(canvas);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 计算文字高
     */
    private  void MeasureText(){
        rect=new Rect();
        paint.getTextBounds(text, 0, text.length()-1, rect);
        textheight=rect.bottom-rect.top;
    }
}

最后还要多说一点,关于 canvas.drawText(text, x, y, paint);我之前一直认为其中的两个参数xy指的是绘制文字的中心点,我会通过paint.getTextBound()把文字设置到Rect矩形内,通过rect.width()及rect.height()来获取文字的宽高,最后在通过整个画布的中心点来调整文字的位置,达到文字居中的效果,然而实际上最后的效果并不是我想要的。其实,x默认是这个字符串的左边在屏幕的位置即origin,如果设置了paint.setTextAlign(Paint.Align.CENTER);那就是字符的中心(文字横向居中,但是纵向不会居中),y是指定这个字符baseline在屏幕上的位置,至于baseline 的位置,这里贴上一张图:

在来张清晰的(来自郭神微信公众号):

看到网上有人对此设计进行吐槽,觉得太麻烦,事实上确实有一点,不过看到这张图,不知道大家有没有觉得像我们以前用的英语本里面的格式线~~至于view的坐标这里也贴上一张图片,有兴趣可以看看:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值