Android 圆弧进度条 & 水平进度条 &

作者: liys_android | 来源:发表于2019-07-14 14:32 被阅读25次
    先上效果图:
    loading.gif

    Demo地址: https://github.com/liys666666/LiysProgressView

    以下代码直接复制即可使用, 碰到类似样式的, 可以根据自己需求修改.
    ①. 在arrts.xml添加对应属性.
    ②. 把源码复制过去即可使用.

    1. 圆弧进度条 ArcProgressView
    ArcProgressView.png

    属性:

    <!-- 圆弧进度条 -->
        <declare-styleable name="ArcProgressView">
            <attr name="liys_progress_arc_text" format="string"/> //中间文字
            <attr name="liys_progress_arc_textSize" format="dimension"/> //文字大小
            <attr name="liys_progress_arc_textColor" format="color"/> //文字颜色
            <attr name="liys_progress_arc_inCircleColor" format="color"/> //进度条 内层颜色
            <attr name="liys_progress_arc_outCircleColor" format="color"/>//进度条 外层颜色
            <attr name="liys_progress_arc_inCircleSize" format="dimension"/>//进度条 内层大小
            <attr name="liys_progress_arc_outCircleSize" format="dimension"/>//进度条 外层大小
            <attr name="liys_progress_arc_startAngle" format="integer"/> //开始角度
            <attr name="liys_progress_arc_drawAngle" format="integer"/> //绘制角度,默认360, 例如:180时为一个半圆
        </declare-styleable>
    

    使用: 其它View使用方式一样

    <com.liys.liysprogressview.ArcProgressView
            android:id="@+id/arc_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="200dp"
            app:liys_progress_arc_inCircleColor="#EDEDED"
            app:liys_progress_arc_textSize="15dp"
            app:liys_progress_arc_text="0%"/>
    
    2. 线性进度条 LineTextProgressView
    LineTextProgressView.png
    属性:
    <!-- 线性进度条(带文字) -->
        <declare-styleable name="LineTextProgressView">
            <attr name="liys_progress_line_text" format="string"/>  //文字
            <attr name="liys_progress_line_textSize" format="dimension"/> //文字大小
            <attr name="liys_progress_line_textColor" format="color"/> //文字颜色
            <!--<attr name="liys_progress_line_labelColor" format="color"/> -->
            <attr name="liys_progress_line_inLineSize" format="dimension"/>  //进度条 内层大小
            <attr name="liys_progress_line_outLineSize" format="dimension"/> //进度条 外层大小
            <attr name="liys_progress_line_inLineColor" format="color"/> //进度条 内层颜色
            <attr name="liys_progress_line_outLineColor" format="color"/> //进度条 外层颜色
        </declare-styleable>
    
    3. 水平进度条(带文字) HorzTextProgressView
    HorzTextProgressView.png

    属性

    <!-- 水平进度条 (带文字)-->
        <declare-styleable name="HorzTextProgressView"> 
            <attr name="liys_progress_horz_text" format="string"/>  //文字
            <attr name="liys_progress_horz_textSize" format="dimension"/> //文字大小
            <attr name="liys_progress_horz_textColor" format="color"/> //文字颜色
            <!--<attr name="liys_progress_horz_labelColor" format="color"/>-->
            <attr name="liys_progress_horz_inLineSize" format="dimension"/>  //进度条 内层大小
            <attr name="liys_progress_horz_outLineSize" format="dimension"/>  //进度条 外层大小
            <attr name="liys_progress_horz_inLineColor" format="color"/> //进度条 内层颜色
            <attr name="liys_progress_horz_outLineColor" format="color"/> //进度条 外层颜色
        </declare-styleable>
    
    4. 水平进度条(不带文字) HorzProgressView
    HorzProgressView.png
    属性:
    <!-- 水平进度条(不带文字)-->
        <declare-styleable name="HorzProgressView">
            <attr name="liys_progress_line_max" format="integer"/> //最大值
            <attr name="liys_progress_line_progress" format="integer"/> //当前进度值
            <attr name="liys_progress_line_outSize" format="dimension"/> //进度条 外层大小
            <attr name="liys_progress_line_inColor" format="color"/> //进度条 内层颜色
            <attr name="liys_progress_line_outColor" format="color"/> //进度条 外层颜色
            <attr name="liys_progress_line_inDrawable" format="reference"/> //进度条 内层图片(可选)
            <attr name="liys_progress_line_outDrawable" format="reference"/> //进度条 外层图片(可选)
        </declare-styleable>
    
    5. 水波 进度条 WaterWaveProView
    WaterWaveProView.png
    属性:
    <!-- 水波 进度条 -->
        <declare-styleable name="WaterWaveProView">
            <attr name="liys_progress_water_text" format="string"/> //中间文字内容
            <attr name="liys_progress_water_textSize" format="dimension"/> //文字大小
            <attr name="liys_progress_water_textColor" format="color"/> //文字颜色
            <attr name="liys_progress_water_inColor" format="color"/> //内层颜色
            <attr name="liys_progress_water_waterColor" format="color"/> //外层颜色
        </declare-styleable>
    
    >>>>>>>>>>>>>>>>>>>>>>>>附上源码>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    /**
     * 圆弧进度条
     * @author liys  401654546@qq.com
     * @version 1.0  2018/09/12
     */
    public class ArcProgressView extends View {
    
        private double mMaxNum = 10000; //最大值
        private double mCurrentNum = 0; //当前的值
        private String mText = "0%"; //当前 百分比
    
        private int mTextSize;  //字体大小
    
        private int mTextColor = 0; //字体颜色
        private int mInColor = 0; //内圈颜色
        private int mOutColor = 0; //外圈颜色
    
        private int mInCircleSize; //外圈大小 单位sp
        private int mOutCircleSize; //内圈大小 单位sp
    
        private int mStartAngle; //开始角度
        private int mDrawAngle; //需要绘制的角度
        private int mCurrentAngle = 0; //当前角度
    
        private int mWidth; //宽
        private int mHeight; //高
        int defaultWidth = 100; //默认宽高,单位sp
    
        //画笔
        private Paint mTextPaint;
        private Paint mInPaint;
        private Paint mOutPaint;
    
        public ArcProgressView(Context context) {
            this(context, null, 0);
    
        }
    
        public ArcProgressView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ArcProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            //默认值
            int defaultTextSize = 20;  //默认字体大小
            int defaultCircleSize = 10; //默认圆弧大小 单位sp
            int defaultStartAngle = -90; //默认开始角度
            int defaultDrawAngle = 360; //默认绘制角度
            String defaultTextColor = "#ABC4DF"; //默认字体颜色
            String defaultInColor = "#EDEDED"; //默认内颜色
            String defaultOutColor = "#CCBD00"; //默认外颜色
    
            // 获取自定义属性
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ArcProgressView);
    
            mText = typedArray.getString(R.styleable.ArcProgressView_liys_progress_arc_text);
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_liys_progress_arc_textSize, sp2px(defaultTextSize));
    
            mStartAngle = typedArray.getInt(R.styleable.ArcProgressView_liys_progress_arc_startAngle, defaultStartAngle);
            mDrawAngle = typedArray.getInt(R.styleable.ArcProgressView_liys_progress_arc_drawAngle, defaultDrawAngle);
    
            mTextColor = typedArray.getColor(R.styleable.ArcProgressView_liys_progress_arc_textColor, Color.parseColor(defaultTextColor));
            mInColor = typedArray.getColor(R.styleable.ArcProgressView_liys_progress_arc_inCircleColor, Color.parseColor(defaultInColor));
            mOutColor = typedArray.getColor(R.styleable.ArcProgressView_liys_progress_arc_outCircleColor, Color.parseColor(defaultOutColor));
    
            mInCircleSize = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_liys_progress_arc_inCircleSize, sp2px(defaultCircleSize));
            mOutCircleSize = typedArray.getDimensionPixelSize(R.styleable.ArcProgressView_liys_progress_arc_outCircleSize, sp2px(defaultCircleSize));
            typedArray.recycle();
    
            //设置画笔
            mTextPaint = new Paint();
            mInPaint = new Paint();
            mOutPaint = new Paint();
    
            setTextPaint();
            setInPaint();
            setOutPaint();
        }
    
        /**
         * 文字画笔
         */
        private void setTextPaint() {
            mTextPaint.setColor(mTextColor);
            mTextPaint.setAntiAlias(true);
            mTextPaint.setTextSize(mTextSize);
        }
    
        /**
         * 内圆弧画笔
         */
        private void setInPaint() {
            mInPaint.setColor(mInColor);
            mInPaint.setAntiAlias(true);
            mInPaint.setStrokeWidth(mInCircleSize); //大小
            mInPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
            mInPaint.setStyle(Paint.Style.STROKE); //空心样式
        }
    
        /**
         * 外圆弧画笔
         */
        private void setOutPaint() {
            mOutPaint.setColor(mOutColor);
            mOutPaint.setAntiAlias(true);
            mOutPaint.setStrokeWidth(mOutCircleSize); //大小
            mOutPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
            mOutPaint.setStyle(Paint.Style.STROKE); //空心样式
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //取默认值
            mWidth = sp2px(defaultWidth);
            mHeight = sp2px(defaultWidth);
            //1. 获取宽
            if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
            }
            //2.获取高
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
            //3. 确定宽高(保持宽高一致)
            mWidth = mHeight = (mWidth > mHeight ? mHeight : mWidth);
            setMeasuredDimension(mWidth, mHeight);
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            drawText(canvas);
            drawInCircle(canvas);
            drawOutCircle(canvas);
        }
    
        //内圆弧
        private void drawInCircle(Canvas canvas) {
            int r = mInCircleSize / 2; //圆弧的一半
            RectF rectF = new RectF(r, r, mWidth - r, mHeight - r);
            canvas.drawArc(rectF, mStartAngle, mDrawAngle, false, mInPaint);
        }
    
        //内圆弧
        private void drawOutCircle(Canvas canvas) {
            int r = mOutCircleSize / 2; //圆弧的一半
            RectF rectF = new RectF(r, r, mWidth - r, mHeight - r);
            if (mCurrentAngle > mDrawAngle) {
                mCurrentAngle = mDrawAngle;
            }
            canvas.drawArc(rectF, mStartAngle, mCurrentAngle, false, mOutPaint);
        }
    
        private void drawText(Canvas canvas) {
            //1. 获取绘制字体区域
            Rect bounds = new Rect();
            mTextPaint.getTextBounds(mText, 0, mText.length(), bounds);
            //2.获取准线
            Paint.FontMetricsInt metrics = mTextPaint.getFontMetricsInt();
            int dy = (metrics.bottom - metrics.top) / 2 - metrics.bottom;
            int baseLine = mHeight / 2 + dy;
            //3.绘制文字
            canvas.drawText(mText, mWidth / 2 - bounds.width() / 2, baseLine, mTextPaint);
        }
    
        private int sp2px(int sp) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
                    getResources().getDisplayMetrics());
        }
    
        public void setMaxNum(double maxNum) {
            this.mMaxNum = maxNum;
        }
    
        public void setCurrentNum(double currentNum) {
            this.mCurrentNum = currentNum;
            //计算角度 mCurrentStep/mMaxStep = mCurrentAngle/mDrawAngle;
            mCurrentAngle = (int)(currentNum * mDrawAngle / mMaxNum);
            mText =  new DecimalFormat("0.00%").format(mCurrentNum/mMaxNum);
            invalidate();
        }
    }
    
    /**
     * 线性进度条
     * @author liys  401654546@qq.com
     * @version 1.0  2018/09/12
     */
    public class LineTextProgressView extends View{
    
        private double mMaxNum = 10000; //最大值
        private double mCurrentNum = 0; //当前的值
        private String mText = "0%"; //当前 百分比
    
        private int mTextSize;  //字体大小
    
        private int mTextColor = 0; //字体颜色
        private int mInLineColor = 0; //内线颜色
        private int mOutLineColor = 0; //外线颜色
    
        private int mInLineSize; //外线 大小 单位sp
        private int mOutLineSize; //内线 大小 单位sp
    
        private int mWidth; //宽
        private int mHeight; //高
        int mDefaultWidth = 300; //默认宽,单位sp
        int mDefaultHeight = 30; //默认高,单位sp
    
        int mTriangleValue = 8;
        
    
        //画笔
        private Paint mTextPaint;
        private Paint mInPaint;
        private Paint mOutPaint;
        private Paint mBoxPaint;
    
        public LineTextProgressView(Context context) {
            this(context, null);
        }
    
        public LineTextProgressView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public LineTextProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            //默认值
            int defaultTextSize = 10;  //默认字体大小 单位sp
            String defaultTextColor = "#FFFFFF"; //默认字体颜色
            String defaultInColor = "#EDEDED"; //默认内颜色
            String defaultOutColor = "#CCBD00"; //默认外颜色
            int defaultLineSize = 10; //默认线的大小 单位sp
    
            
            // 获取自定义属性
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LineTextProgressView);
    
            mText = typedArray.getString(R.styleable.LineTextProgressView_liys_progress_line_text);
            mTextColor = typedArray.getColor(R.styleable.LineTextProgressView_liys_progress_line_textColor, Color.parseColor(defaultTextColor));
            mInLineColor = typedArray.getColor(R.styleable.LineTextProgressView_liys_progress_line_inLineColor, Color.parseColor(defaultInColor));
            mOutLineColor = typedArray.getColor(R.styleable.LineTextProgressView_liys_progress_line_outLineColor, Color.parseColor(defaultOutColor));
    
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.LineTextProgressView_liys_progress_line_textSize, sp2px(defaultTextSize));
            mInLineSize = typedArray.getDimensionPixelSize(R.styleable.LineTextProgressView_liys_progress_line_inLineSize, sp2px(defaultLineSize));
            mOutLineSize = typedArray.getDimensionPixelSize(R.styleable.LineTextProgressView_liys_progress_line_outLineSize, sp2px(defaultLineSize));
            typedArray.recycle();
    
            setTextPaint();
            setInPaint();
            setOutPaint();
            setBoxPaint();
    
            if(mText == null){
                mText = "00.00%";
            }
        }
    
        /**
         * 方框画笔
         */
        private void setBoxPaint() {
            mBoxPaint = new Paint();
            mBoxPaint.setAntiAlias(true);
            mBoxPaint.setColor(mOutLineColor);
        }
        /**
         * 文字画笔
         */
        private void setTextPaint() {
            mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setColor(mTextColor);
            mTextPaint.setTextSize(mTextSize);
        }
    
        /**
         * 内线画笔
         */
        private void setInPaint() {
            mInPaint = new Paint();
            mInPaint.setAntiAlias(true);
            mInPaint.setColor(mInLineColor);
            mInPaint.setStrokeWidth(mInLineSize); //大小
            mInPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
        }
    
        /**
         * 外线画笔
         */
        private void setOutPaint() {
            mOutPaint = new Paint();
            mOutPaint.setAntiAlias(true);
            mOutPaint.setColor(mOutLineColor);
            mOutPaint.setStrokeWidth(mOutLineSize); //大小
            mOutPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //取默认值
            mWidth = sp2px(mDefaultWidth);
            mHeight = sp2px(mDefaultHeight);
            //1. 获取宽
            if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
            }
            //2.获取高
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
            //2. 确定宽高
            setMeasuredDimension(mWidth, mHeight);
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //1 确定文字外框区域
            Rect bounds = new Rect();
            String str = "100.00%";
            mTextPaint.getTextBounds(str, 0, str.length(), bounds);
    
            int boxWidth = bounds.width() + sp2px(5);
            int boxHeight = bounds.height() + sp2px(10);
            int outWidth = (int)(mCurrentNum/mMaxNum * (mWidth-boxWidth)); //计算当前进度距离
            drawBox(canvas, outWidth, boxWidth, boxHeight); //绘制外框
    
            //2 画文字
            Paint.FontMetricsInt metrics = mTextPaint.getFontMetricsInt();
            int dy = (metrics.bottom - metrics.top) / 2 - metrics.bottom;
            int baseLine = boxHeight / 2 + dy; //基线
    
            //文字变化的时候 为了保证文字居中 所以需要知道文字区域大小
            Rect bound = new Rect();
            mTextPaint.getTextBounds(mText, 0, mText.length(), bound); //获取文字区域大小
            canvas.drawText(mText, outWidth + (boxWidth/2 - bound.width()/2), baseLine, mTextPaint);
    
    
            //3. 画进度条
            //方式一:推荐
            drawHLine(canvas, boxWidth/2, (boxHeight+sp2px(mTriangleValue)),mWidth, mHeight, mInPaint); //画内线
            drawHLine(canvas, boxWidth/2, (boxHeight+sp2px(mTriangleValue)),boxWidth/2 + outWidth, mHeight, mOutPaint); //画外线
    
            //方式一:不推荐
    //        int lineHeight = mHeight-boxHeight-sp2px(mTriangleValue);
    //        drawInLine(canvas, boxWidth/2, mWidth - boxWidth/2, lineHeight, mInPaint); //画内线
    //        drawOutLine(canvas, boxWidth/2,  boxWidth/2 + outWidth, lineHeight, mOutPaint); //画外线
        }
    
        /**
         * @param canvas
         * @param left 左边距离
         * @param width 矩形 宽
         * @param height 矩形 高
         */
        public void drawBox(Canvas canvas, int left, int width, int height){
            //2.1 画圆角矩形
            RectF rectF = new RectF(left, 0, width + left, height);// 设置个新的长方形
            canvas.drawRoundRect(rectF, height/4, height/4, mBoxPaint);//第二个参数是x半径,第三个参数是y半径
            //2.2 画三角形 (绘制这个三角形,你可以绘制任意多边形)
            Path path = new Path();
            path.moveTo(left + width/2-sp2px(4), height);// 此点为多边形的起点
            path.lineTo(left + width/2+sp2px(4), height);
            path.lineTo(left + width/2, height + sp2px(5));
            path.close(); // 使这些点构成封闭的多边形
            canvas.drawPath(path, mBoxPaint);
        }
    
        /**
         * 水平进度条(前进方向平的) 通用
         * @param canvas
         * @param left
         * @param top
         * @param right
         * @param bottom
         * @param paint
         */
        public void drawHLine(Canvas canvas, int left, int top, int right, int bottom, Paint paint){
            int height = bottom - top; //高度
            int r = height/2; //半径
            int cFirstX = left + r; //第一个分割点x坐标
            int cSecondX = mWidth - left - r; //第二个分割点x坐标
            int cy = top + r; //圆心y坐标
    
            //1. 绘制第一个圆
            canvas.save();
            canvas.clipRect(new RectF(left, top, right, bottom));
            canvas.drawCircle(left+r, cy, r, paint);
            canvas.restore();
    
            //2. 绘制中间矩形
            if(right >= cFirstX){
                canvas.save();
                int currentRight = right;
                if(right > cSecondX){
                    currentRight = cSecondX;
                }
                canvas.drawRect(new RectF(left+r, top, currentRight, bottom), paint);
                canvas.restore();
            }
    
            //3. 绘制最后的圆
            if(right >= cSecondX){
                canvas.save();
                canvas.clipRect(new RectF(cSecondX, top, right, bottom));
                canvas.drawCircle(cSecondX, cy, r, paint);
                canvas.restore();
            }
        }
    
        public void drawInLine(Canvas canvas, int left, int width, int height, Paint paint){
            RectF rectF = new RectF(left, mHeight-height, width, mHeight); // 设置个新的长方形
            canvas.drawRoundRect(rectF, height/2, height/2, paint); //第二个参数是x半径,第三个参数是y半径
        }
    
        //进度前进方向为圆角
        public void drawOutLine(Canvas canvas, int left, int width, int height, Paint paint){
            if((width-left) >= height){ //绘制圆角方式
                RectF rectF = new RectF(left, mHeight-height, width, mHeight); // 设置个新的长方形
                canvas.drawRoundRect(rectF, height/2, height/2, paint); //第二个参数是x半径,第三个参数是y半径
            }
            //绘制前面圆
            RectF rectF = new RectF(left, mHeight-height, width, mHeight);
            canvas.clipRect(rectF);
            int r = height/2;
            canvas.drawCircle(left+r, mHeight-height+r, r, paint);
        }
    
        private int sp2px(int sp) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
                    getResources().getDisplayMetrics());
        }
    
        public void setCurrentNum(double currentNum) {
            this.mCurrentNum = currentNum;
            if(mCurrentNum > mMaxNum){
                mCurrentNum = mMaxNum;
            }
            mText = new DecimalFormat("0.00%").format(mCurrentNum/mMaxNum);
            invalidate();
        }
    }
    
    /**
     * 水平进度条(带文字)
     * @author liys  401654546@qq.com
     * @version 1.0  2018/09/12
     */
    public class HorzTextProgressView extends View{
    
        private double mMaxNum = 10000; //最大值
        private double mCurrentNum = 0; //当前的值
        private String mText = "0%"; //当前 百分比
    
        private int mTextSize;  //字体大小
    
        private int mTextColor = 0; //字体颜色
        private int mInLineColor = 0; //内线颜色
        private int mOutLineColor = 0; //外线颜色
    
        private int mInLineSize; //外线 大小 单位sp
        private int mOutLineSize; //内线 大小 单位sp
    
        private int mWidth; //宽
        private int mHeight; //高
        private int mDefaultWidth = 300; //默认宽,单位sp
        private int mDefaultHeight = 20; //默认高,单位sp
    
        int boxWidth = 30; //文字框 宽 单位sp
    
        //画笔
        private Paint mTextPaint;
        private Paint mInPaint;
        private Paint mOutPaint;
        private Paint mBoxPaint;
    
        public HorzTextProgressView(Context context) {
            this(context, null);
        }
    
        public HorzTextProgressView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public HorzTextProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            //默认值
            int defaultTextSize = 10;  //默认字体大小 单位sp
            String defaultTextColor = "#FFFFFF"; //默认字体颜色
            String defaultInColor = "#EDEDED"; //默认内颜色
            String defaultOutColor = "#CCBD00"; //默认外颜色
            int defaultLineSize = 10; //默认线的大小 单位sp
    
            
            // 获取自定义属性
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HorzTextProgressView);
    
            mText = typedArray.getString(R.styleable.HorzTextProgressView_liys_progress_horz_text);
            mTextColor = typedArray.getColor(R.styleable.HorzTextProgressView_liys_progress_horz_textColor, Color.parseColor(defaultTextColor));
            mInLineColor = typedArray.getColor(R.styleable.HorzTextProgressView_liys_progress_horz_inLineColor, Color.parseColor(defaultInColor));
            mOutLineColor = typedArray.getColor(R.styleable.HorzTextProgressView_liys_progress_horz_outLineColor, Color.parseColor(defaultOutColor));
    
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.HorzTextProgressView_liys_progress_horz_textSize, sp2px(defaultTextSize));
            mInLineSize = typedArray.getDimensionPixelSize(R.styleable.HorzTextProgressView_liys_progress_horz_inLineSize, sp2px(defaultLineSize));
            mOutLineSize = typedArray.getDimensionPixelSize(R.styleable.HorzTextProgressView_liys_progress_horz_outLineSize, sp2px(defaultLineSize));
            typedArray.recycle();
    
            setTextPaint();
            setInPaint();
            setOutPaint();
            setBoxPaint();
            if(mText == null){
                mText = "0%";
            }
            boxWidth = sp2px(boxWidth);
        }
    
        /**
         * 方框画笔
         */
        private void setBoxPaint() {
            mBoxPaint = new Paint();
            mBoxPaint.setAntiAlias(true);
            mBoxPaint.setColor(mOutLineColor);
        }
        /**
         * 文字画笔
         */
        private void setTextPaint() {
            mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setColor(mTextColor);
            mTextPaint.setTextSize(mTextSize);
        }
    
        /**
         * 内线画笔
         */
        private void setInPaint() {
            mInPaint = new Paint();
            mInPaint.setAntiAlias(true);
            mInPaint.setColor(mInLineColor);
            mInPaint.setStrokeWidth(mInLineSize); //大小
            mInPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
        }
    
        /**
         * 外线画笔
         */
        private void setOutPaint() {
            mOutPaint = new Paint();
            mOutPaint.setAntiAlias(true);
            mOutPaint.setColor(mOutLineColor);
            mOutPaint.setStrokeWidth(mOutLineSize); //大小
            mOutPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //取默认值
            mWidth = sp2px(mDefaultWidth);
            mHeight = sp2px(mDefaultHeight);
            //1. 获取宽
            if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
            }
            //2.获取高
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
            //2. 确定宽高
            setMeasuredDimension(mWidth, mHeight);
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //1. 获取当前进度
            int outWidth = (int)(mCurrentNum/mMaxNum * mWidth); //计算当前进度距离
            if(outWidth >= mWidth - boxWidth){
                outWidth = (mWidth - boxWidth);
            }
    
            //2. 画进度条
            int inTop = (mHeight - mInLineSize)/2;
            int outTop = (mHeight - mOutLineSize)/2;
            drawHLine(canvas, 0, inTop, mWidth, mHeight - inTop, mInPaint); //画内线
            drawHLine(canvas, 0, outTop, outWidth+sp2px(2), mHeight - outTop, mOutPaint); //画外线
    
            //3. 画文字框
            drawBox(canvas, outWidth, boxWidth, mHeight);
    
            //4. 画文字
            Paint.FontMetricsInt metrics = mTextPaint.getFontMetricsInt();
            int dy = (metrics.bottom - metrics.top) / 2 - metrics.bottom;
            int baseLine = mHeight/2 + dy; //基线
    
            //文字变化的时候 为了保证文字居中 所以需要知道文字区域大小
            Rect bound = new Rect();
            mTextPaint.getTextBounds(mText, 0, mText.length(), bound); //获取文字区域大小
            canvas.drawText(mText, outWidth + (boxWidth/2 - bound.width()/2), baseLine, mTextPaint);
        }
    
        /**
         * @param canvas
         * @param left 左边距离
         * @param width 矩形 宽
         * @param height 矩形 高
         */
        public void drawBox(Canvas canvas, int left, int width, int height){
            RectF rectF = new RectF(left, 0, width + left, height); // 设置个新的长方形
            canvas.drawRoundRect(rectF, height/2, height/2, mBoxPaint); //第二个参数是x半径,第三个参数是y半径
        }
    
        /**
         * 水平进度条(前进方向平的) 通用
         * @param canvas
         * @param left
         * @param top
         * @param right
         * @param bottom
         * @param paint
         */
        public void drawHLine(Canvas canvas, int left, int top, int right, int bottom, Paint paint){
            int height = bottom - top; //高度
            int r = height/2; //半径
            int cFirstX = left + r; //第一个分割点x坐标
            int cSecondX = mWidth - left - r; //第二个分割点x坐标
            int cy = top + r; //圆心y坐标
    
            //1. 绘制第一个圆
            canvas.save();
            canvas.clipRect(new RectF(left, top, right, bottom));
            canvas.drawCircle(left+r, cy, r, paint);
            canvas.restore();
    
            //2. 绘制中间矩形
            if(right >= cFirstX){
                canvas.save();
                int currentRight = right;
                if(right > cSecondX){
                    currentRight = cSecondX;
                }
                canvas.drawRect(new RectF(left+r, top, currentRight, bottom), paint);
                canvas.restore();
            }
    
            //3. 绘制最后的圆
            if(right >= cSecondX){
                canvas.save();
                canvas.clipRect(new RectF(cSecondX, top, right, bottom));
                canvas.drawCircle(cSecondX, cy, r, paint);
                canvas.restore();
            }
        }
        private int sp2px(int sp) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
                    getResources().getDisplayMetrics());
        }
    
        public void setCurrentNum(double currentNum) {
            this.mCurrentNum = currentNum;
            if(mCurrentNum > mMaxNum){
                mCurrentNum = mMaxNum;
            }
            mText = new DecimalFormat("0%").format(mCurrentNum/mMaxNum);
            invalidate();
        }
    }
    
    **
     * liys 2019-01-13
     * 水平进度条(不带文字)
     */
    public class HorzProgressView extends View{
    
        private double mMaxNum = 100; //最大值
        private double mCurrentNum = 0; //当前的值
    
        private int mInLineColor = 0; //内线颜色
        private int mOutLineColor = 0; //外线颜色
        private Drawable mInLineDrawable = null; //内线图片
        private Drawable mOutLineDrawable = null; //外线图片
    
        private int mOutLineSize; //外线 大小 单位sp
    
        private int mWidth; //宽
        private int mHeight; //高
    
        //画笔
        private Paint mInPaint;
        private Paint mOutPaint;
        private Paint mPaint = new Paint(); //绘制图片
    
        public HorzProgressView(Context context) {
            this(context, null);
        }
    
        public HorzProgressView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public HorzProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
    
            // 获取自定义属性
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HorzProgressView);
    
            mCurrentNum = typedArray.getInteger(R.styleable.HorzProgressView_liys_progress_line_progress, 0);
            mMaxNum = typedArray.getInteger(R.styleable.HorzProgressView_liys_progress_line_max, 100);
    
            //颜色
            mInLineColor = typedArray.getColor(R.styleable.HorzProgressView_liys_progress_line_inColor, 0);
            mOutLineColor = typedArray.getColor(R.styleable.HorzProgressView_liys_progress_line_outColor, 0);
    
            //图片
            mInLineDrawable = typedArray.getDrawable(R.styleable.HorzProgressView_liys_progress_line_inDrawable);
            mOutLineDrawable = typedArray.getDrawable(R.styleable.HorzProgressView_liys_progress_line_outDrawable);
    
            //大小
            mOutLineSize = typedArray.getDimensionPixelSize(R.styleable.HorzProgressView_liys_progress_line_outSize, 0);
    
            typedArray.recycle();
    
            setInPaint();
            setOutPaint();
        }
    
        /**
         * 内线画笔
         */
        private void setInPaint() {
            mInPaint = new Paint();
            mInPaint.setAntiAlias(true);
            mInPaint.setColor(mInLineColor);
            mInPaint.setStrokeWidth(mHeight); //大小
            mInPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
        }
    
        /**
         * 外线画笔
         */
        private void setOutPaint() {
            mOutPaint = new Paint();
            mOutPaint.setAntiAlias(true);
            mOutPaint.setColor(mOutLineColor);
            mOutPaint.setStrokeWidth(mOutLineSize); //大小
            mOutPaint.setStrokeCap(Paint.Cap.ROUND); // 结束位置圆角
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //1. 获取宽
            if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
            }
            //2.获取高
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
            if(mOutLineSize == 0){
                mOutLineSize = mHeight;
            }
            //2. 确定宽高
            setMeasuredDimension(mWidth, mHeight);
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //内层
            if(mInLineColor != 0){
                drawInLine(canvas, 0, mWidth, mHeight, mInPaint); //画内线
            }
            if(mInLineDrawable != null){
                Bitmap bitmap = ((BitmapDrawable) mInLineDrawable).getBitmap();
                canvas.drawBitmap(bitmap, null, new Rect(0,0, mWidth, mHeight), mPaint);
            }
    
            //外层
            int left = (mHeight-mOutLineSize)/2;
            int width = (int)((mWidth-left)*(mCurrentNum/mMaxNum));
            if(mOutLineColor != 0){
                drawOutLine(canvas, left, width, mOutLineSize, mOutPaint); //画外线
            }
            if(mOutLineDrawable != null){
                Bitmap bitmap = ((BitmapDrawable) mOutLineDrawable).getBitmap();
                canvas.drawBitmap(bitmap, null, new Rect(left,(mHeight-mOutLineSize)/2, width, mOutLineSize), mPaint);
            }
        }
    
        public void drawInLine(Canvas canvas, int left, int width, int height, Paint paint){
            RectF rectF = new RectF(left, mHeight-height, width, mHeight); // 设置个新的长方形
            canvas.drawRoundRect(rectF, height/2, height/2, paint); //第二个参数是x半径,第三个参数是y半径
        }
    
        /**
         * 进度前进方向为圆角
         */
        public void drawOutLine(Canvas canvas, int left, int width, int height, Paint paint){
            int top = (mHeight-height)/2;
            if((width-left) >= height){ //绘制圆角方式
    //            RectF rectF = new RectF(left, mHeight-height, width, mHeight); // 设置个新的长方形
                RectF rectF = new RectF(left, top, width, mHeight-top); // 设置个新的长方形
                canvas.drawRoundRect(rectF, height/2, height/2, paint); //第二个参数是x半径,第三个参数是y半径
            }
            //绘制前面圆
            RectF rectF = new RectF(left, top, width, mHeight-top);
            canvas.clipRect(rectF);
            int r = height/2;
            canvas.drawCircle(left+r, top+r, r, paint);
        }
    
        public void setMax(double max){
            this.mMaxNum = max;
            invalidate();
        }
    
        public void setCurrentNum(double currentNum) {
            this.mCurrentNum = currentNum;
            if(mCurrentNum > mMaxNum){
                mCurrentNum = mMaxNum;
            }
            invalidate();
        }
    }
    
    
    /**
     * 水波进度条
     * @author liys  401654546@qq.com
     * @version 1.0  2018/09/12
     */
    public class WaterWaveProView extends View {
    
        private double mMaxNum = 10000; //最大值
        private double mCurrentNum = 0; //当前的值
        private double mPercent = 0.0; //百分比
    
        private String mText = ""; //当前 百分比
        private int mTextSize;  //字体大小
        private int mTextColor;  //字体大小
    
        private int mInColor = 0; //里面颜色
        private int mWaterColor = 0; //水波颜色
    
        //控件宽高
        private int mWidth;
        private int mHeight;
        int mDefaultWidthHeight= 100; //默认宽高,单位sp
    
        private float mStartX = 0; //开始位置
        private int mWaveWidth; //水波长
        private int mWaveHeight; //水波高度
        private Paint mPaint;
        private Paint mTextPaint;
        private Path mPath;
    
        public WaterWaveProView(Context context) {
            this(context, null);
        }
    
        public WaterWaveProView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WaterWaveProView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);//关闭硬件加速
    
            //默认值
            int defaultTextSize = 20;  //默认字体大小 单位sp
            String defaultTextColor = "#FFFFFF"; //默认字体颜色
            String defaultInColor = "#69B655"; //默认里面颜色
            String defaultWaterColor = "#0AA328"; //默认水波颜色
    
            // 获取自定义属性
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WaterWaveProView);
            mText = typedArray.getString(R.styleable.WaterWaveProView_liys_progress_water_text);
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.WaterWaveProView_liys_progress_water_textSize, sp2px(defaultTextSize));
            mTextColor = typedArray.getColor(R.styleable.WaterWaveProView_liys_progress_water_textColor, Color.parseColor(defaultTextColor));
            mWaterColor = typedArray.getColor(R.styleable.WaterWaveProView_liys_progress_water_waterColor, Color.parseColor(defaultInColor));
            mInColor = typedArray.getColor(R.styleable.WaterWaveProView_liys_progress_water_inColor, Color.parseColor(defaultWaterColor));
            typedArray.recycle();
    
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setColor(mWaterColor);
    
            mTextPaint = new Paint();
            mTextPaint.setAntiAlias(true);
            mTextPaint.setColor(mTextColor);
            mTextPaint.setTextSize(mTextSize);
    
            mPath = new Path();
    
            if(mText == null){
                mText = "0.00%";
            }
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            int defaultWaterHeight = 5; //默认水波高度 单位sp
            //1.取默认宽高
            mWidth = sp2px(mDefaultWidthHeight);
            mHeight = sp2px(mDefaultWidthHeight);
            //2. 获取宽
            if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mWidth = MeasureSpec.getSize(widthMeasureSpec);
            }
            //3.获取高
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { //具体值
                mHeight = MeasureSpec.getSize(heightMeasureSpec);
            }
            //4. 确定宽高(保持宽高一致)
            mWidth = mHeight = (mWidth > mHeight ? mHeight : mWidth);
            //5. 确定波长和波高
            mWaveWidth = mWidth/4;
            mWaveHeight = sp2px(defaultWaterHeight);
            setMeasuredDimension(mWidth, mHeight);
            start();
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            //1. 绘制贝塞尔曲线
            drawBessel(mWidth, mStartX, (int)(mHeight*(1-mPercent)), mWaveWidth, mWaveHeight, mPath, mPaint);
            canvas.drawPath(mPath, mPaint);
            //2. 设置模式
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
            //3. 绘制圆形bitmap
            canvas.drawBitmap(createCircleBitmap(mWidth/2, mInColor), null, new Rect(0,0,mWidth,mHeight), mPaint);
            //4. 绘制文字
            drawText(canvas, mText, mWidth, mHeight, mTextPaint);
        }
    
        /**
         * 绘制贝塞尔曲线
         * @param width 总共需要绘制的长度
         * @param startX 开始X点坐标(-2*startX 到 0 之间) 左右预留一个波长
         * @param startY 开始Y坐标
         * @param waveWidth 波长(半个周期)
         * @param waveHeight 波高
         * @param path
         * @param paint 画笔
         */
        private void drawBessel(float width, float startX, float startY, float waveWidth, float waveHeight, Path path, Paint paint){
            //Android贝塞尔曲线
            // 二阶写法:rQuadTo(float dx1, float dy1, float dx2, float dy2) 相对上一个起点的坐标
            path.reset();
            int currentWidth = 0; //当前已经绘制的宽度
            path.moveTo(startX,startY); //画笔位置
            while (currentWidth <= width + 4*waveWidth && waveWidth>0){
                path.rQuadTo(waveWidth, -waveHeight, 2*waveWidth, 0);
                path.rQuadTo(waveWidth, waveHeight, 2*waveWidth, 0);
                currentWidth += 2*waveWidth;
            }
            //封闭的区域
            mPath.lineTo(getWidth()+4*waveWidth,getHeight());
            mPath.lineTo(0,getHeight());
            path.close();
        }
    
        private Bitmap createCircleBitmap(int radius, int color){
            Bitmap canvasBmp = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(canvasBmp);
            canvas.drawColor(Color.TRANSPARENT);
            Paint paint = new Paint();
            paint.setColor(color);
            canvas.drawCircle(radius, radius, radius, paint); //确定位置
            return canvasBmp;
        }
    
        /**
         * 绘制文字  居中
         * @param canvas
         * @param text 文字内容
         * @param width 绘制区域 宽
         * @param height 绘制区域 高
         * @param paint
         */
        public void drawText(Canvas canvas, String text, int width, int height, Paint paint){
            Rect bounds = new Rect();
            paint.getTextBounds(text,0, mText.length(), bounds);
            Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
            int dy = (metrics.bottom - metrics.top) / 2 - metrics.bottom;
            int baseLine = height / 2 + dy; //基线
            canvas.drawText(text, width/2-bounds.width()/2, baseLine, paint);
        }
    
        /**
         * 设置当前进度
         * @param currentNum
         */
        public void setCurrentNum(double currentNum) {
            this.mCurrentNum = currentNum;
            setPercent();
        }
    
        public void setMaxNum(int maxNum){
            this.mMaxNum = maxNum;
            setPercent();
        }
    
        private void setPercent(){
            if(mCurrentNum > mMaxNum){
                mCurrentNum = mMaxNum;
            }
            mPercent = mCurrentNum/mMaxNum;
            mText = new DecimalFormat("0.00%").format(mPercent);
        }
    
        private void setStartX(float startX){
            mStartX = startX;
            invalidate();
        }
    
        private int sp2px(int sp) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
                    getResources().getDisplayMetrics());
        }
    
        private void start(){
            ValueAnimator animator = ValueAnimator.ofFloat(0-4*mWaveWidth, 0);
            animator.setInterpolator(new LinearInterpolator());//匀速插值器 解决卡顿问题
            animator.setDuration(2000);
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    setStartX((float) animation.getAnimatedValue());
                }
            });
            animator.start();
        }
    
    }
    

    相关文章

      网友评论

        本文标题:Android 圆弧进度条 & 水平进度条 &

        本文链接:https://www.haomeiwen.com/subject/oaebkctx.html