Android – 环形进度条

环形进度条

ring_circle_progress.gif

如上图所示,之所以想到写这个,因为项目中有这样的需求,所以自己就去琢磨琢磨该怎么去实现这个需求。 实现思路: ① 画个圆弧 ② 圆弧上画个圆 ③ 画进度条 ④ 在圆弧的中心绘制进度值

好了,思路已经有了,我们现在一个一个来实现。

画个圆弧

canvas.drawArc(rectF, 45, 270, false, mRingPaint);

这样就画了一个我们需要的圆弧。

圆弧上画个圆 画圆就需要圆心和半径。半径比较好得到。这里就半径用到了点数学上的知识。

 float radius = (float) ((width - mArcDis - mArcDis) / 2);
 float pointX = (float) (mCircleX + radius * Math.cos(mSwipeAngle * 3.14 / 180));
 float pointY = (float) (mCircleY + radius * Math.sin(mSwipeAngle * 3.14 / 180));

画进度条 这里的进度条,就是重新绘制一个重合的圆弧

canvas.drawArc(rectF, 45, mSwipeAngle-45, false, mSwipePaint);

在圆弧的中心绘制进度值

float v = mTextPaint.measureText(String.valueOf((int) Math.floor((float) (mSwipeAngle - 45) / 270 * 100)));
canvas.drawText(String.valueOf((int)Math.floor((float)(mSwipeAngle-45)/270*100)),mCircleX-(int)v/2,mCircleY+Px2DpUtil.dp2px(getContext(),10),mTextPaint);
canvas.drawText("%",mCircleX+(int)v/2,mCircleY+Px2DpUtil.dp2px(getContext(),10),mPercentPaint);

下面给出全部代码以供参考:

public class CircleRingView extends View {
    private int mArcDis;
    private Paint mRingPaint;
    private Paint mPointPaint;
    private int mPointAngle;
    private float mCircleX;
    private float mCircleY;
    private int mSwipeAngle=45;

    private Handler mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (mSwipeAngle == mPointAngle) {
                mHandler.removeMessages(0);
            }else {
                ++mSwipeAngle;
                postInvalidate();
            }
        }
    };
    private Paint mSwipePaint;
    private Paint mTextPaint;
    private Paint mPercentPaint;

    public CircleRingView(Context context) {
        this(context, null);
    }

    public CircleRingView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleRingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initParams(context);
    }

    private void initParams(Context context) {
        //圆弧Paint
        mRingPaint = new Paint();
        mRingPaint.setStrokeWidth(Px2DpUtil.dp2px(context, 3));
        mRingPaint.setAntiAlias(true);
        mRingPaint.setStyle(Paint.Style.STROKE);
        mRingPaint.setColor(ContextCompat.getColor(context, R.color.white));
        //圆弧上的圆的Paint
        mPointPaint = new Paint();
        mPointPaint.setStrokeWidth(Px2DpUtil.dp2px(context, 1));
        mPointPaint.setAntiAlias(true);
        mPointPaint.setStyle(Paint.Style.FILL);
        mPointPaint.setColor(ContextCompat.getColor(context, R.color.c_3ec88e));
        //进度条Paint
        mSwipePaint = new Paint();
        mSwipePaint.setStrokeWidth(Px2DpUtil.dp2px(context,3));
        mSwipePaint.setAntiAlias(true);
        mSwipePaint.setStyle(Paint.Style.STROKE);
        mSwipePaint.setColor(ContextCompat.getColor(context, R.color.bg_gradient_start));

        //进度值Paint
        mTextPaint = new Paint();
        mTextPaint.setStrokeWidth(Px2DpUtil.dp2px(context, 1));
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(ContextCompat.getColor(context, R.color.c_3ec88e));
        mTextPaint.setTextSize(Px2DpUtil.sp2px(context,40));

        //百分号Paint
        mPercentPaint = new Paint();
        mPercentPaint.setStrokeWidth(Px2DpUtil.dp2px(context, 1));
        mPercentPaint.setAntiAlias(true);
        mPercentPaint.setStyle(Paint.Style.FILL);
        mPercentPaint.setColor(ContextCompat.getColor(context, R.color.c_3ec88e));
        mPercentPaint.setTextSize(Px2DpUtil.sp2px(context,25));
        //Rectf所需要
        mArcDis = Px2DpUtil.dp2px(context, 20);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        RectF rectF = new RectF();
        rectF.left = mArcDis;
        rectF.top = mArcDis;
        rectF.right = width - mArcDis;
        rectF.bottom = height - mArcDis;
        canvas.rotate(90, width / 2, height / 2);
        //正常圆弧
        canvas.drawArc(rectF, 45, 270, false, mRingPaint);
        if (mSwipeAngle>=0&&mSwipeAngle <= 45) {
            mSwipeAngle = 45;
            mPointAngle=45;
        } else if (mSwipeAngle > 315 & mSwipeAngle <= 360) {
            mSwipeAngle = 315;
            mPointAngle = 315;
        }
        mCircleX = width / 2;
        mCircleY = height / 2;
        if(mSwipeAngle<=mPointAngle) {
            float radius = (float) ((width - mArcDis - mArcDis) / 2);
            float pointX = (float) (mCircleX + radius * Math.cos(mSwipeAngle * 3.14 / 180));
            float pointY = (float) (mCircleY + radius * Math.sin(mSwipeAngle * 3.14 / 180));
            //进度圆弧,模仿进度条
            canvas.drawArc(rectF, 45, mSwipeAngle-45, false, mSwipePaint);
            //圆弧上的圆
            canvas.drawCircle(pointX, pointY, Px2DpUtil.dp2px(getContext(), 10), mPointPaint);
            canvas.rotate(-90, width / 2, height / 2);
            //测量文本宽度
            float v = mTextPaint.measureText(String.valueOf((int) Math.floor((float) (mSwipeAngle - 45) / 270 * 100)));
            //绘制文本
            canvas.drawText(String.valueOf((int)Math.floor((float)(mSwipeAngle-45)/270*100)),mCircleX-(int)v/2,mCircleY+Px2DpUtil.dp2px(getContext(),10),mTextPaint);
            //绘制百分号
            canvas.drawText("%",mCircleX+(int)v/2,mCircleY+Px2DpUtil.dp2px(getContext(),10),mPercentPaint);
            mHandler.sendEmptyMessageDelayed(0, 10);
        }
    }
    //需要画的进度值
    public void setProgressValue(int value){
        int swipeAngle = (int) (((float)value / 100) * 360);
        mPointAngle=  swipeAngle;
        mHandler.sendEmptyMessageDelayed(0, 10);
    }
    //停止绘制View
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mHandler.removeMessages(0);
        mHandler=null;
    }
}

到这里,整个控件的实现方法就都写完了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏lonelydawn的前端猿区

canvas星空的2d绘制示例

一切尽在注释里: <!DOCTYPE html> <html> <head>     <meta charset="utf-8"></meta>     <t...

1999
来自专栏一“技”之长

Android开发之LinearLayout布局详解

        LinaerLayout又被称为线性布局,是Android界面开发中常用的一种容器视图控件。可以使用XML布局文件配置和代码动态创建两种方式来使...

763
来自专栏封碎

Android简单的圆盘形菜单 博客分类: Android Android360

   今天偶然看到一个圆盘形的菜单,还可以转动,感觉挺有意思,然后想了想,做了个简单的效果。       思路是这样的,定一个原点和一个半径,圆的四周均匀...

1062
来自专栏Android开发与分享

【Android】RecyclerView:打造悬浮效果

50410
来自专栏Android知识点总结

Android原生绘图之一起画个表

3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 4----看到这里,我在此感谢你的喜欢与支持

923
来自专栏云加头条

Android图像处理-像素化的原理及实现

像素化(Pixelization),又称马赛克,是图像处理中非常常见的技术,现阶段已经成为了一种创作手段。本文首先会讲解像素化的实现原理,接着会给出Java版的...

4191
来自专栏Android干货

自定义控件详解(八):贝塞尔曲线

1264
来自专栏Android知识点总结

Android关于Path你所知道的和不知道的一切

1046
来自专栏柠檬先生

css3 UI 修饰——回顾

1.box-shadow 属性向框添加一个或者多个阴影。   语法: box-shadow: h-shadow v-shadow blur spread col...

1899
来自专栏指尖下的Android

安卓运动圆环自定义View

记得这个东西原来有个同事问过我,当时正在自学自定义View和属性动画这一块,对这个功能也没有写过,所以就google了一下,发了几个类似效果的github项目给...

1342

扫码关注云+社区