美文网首页
自定义进度条(仿汽车时速表)

自定义进度条(仿汽车时速表)

作者: 玖玖君 | 来源:发表于2019-11-19 10:19 被阅读0次

    我们来看一款非常炫酷的进度自定义控件吧

    /**
     * Created by TU on 2019/11/19.
     */
    public class ArcProgressBar extends View {
        private int diameter = 500;  //直径
        private float centerX;  //圆心X坐标
        private float centerY;  //圆心Y坐标
    
        private Paint allArcPaint;//整个弧形画笔
        private Paint progressPaint;//当前进度的弧形画笔
        private Paint vTextPaint; //内容显示文字画笔
        private Paint hintPaint; //显示单位文字画笔
        private Paint degreePaint;//外部刻度线
        private Paint curSpeedPaint;//显示标题文字
    
        private RectF bgRect;//弧形矩阵区域
    
        private ValueAnimator progressAnimator;//执行进度动画
        private PaintFlagsDrawFilter mDrawFilter;//用于抗锯齿
        private SweepGradient sweepGradient;//梯度渲染,用于渐变
        private Matrix rotateMatrix;//渐变矩阵
    
        private float startAngle = 135;//起始角度
        private float sweepAngle = 270;//最大角度
        private float currentAngle = 0;//当前进度角度
        private float lastAngle;//进度变化时最终角度
        private int[] colors = new int[]{Color.GREEN, Color.YELLOW, Color.RED};//进度渐变三色(左到右渐变)
        private float maxValues = 60;//默认进度最大值
        private float curValues = 0;//默认进度变化值
        private float bgArcWidth = dipToPx(2);//背景进度宽度
        private int bgArcColor;//背景进度颜色
        private float progressWidth = dipToPx(10);//进度宽度
        private float textSize = dipToPx(60);//默认字体大小
        private float hintSize = dipToPx(15);
        private float curSpeedSize = dipToPx(13);
        private int aniSpeed = 1000;//默认动画时长
        private float longdegree = dipToPx(13);//刻度长
        private float shortdegree = dipToPx(5);//刻度短
        private final int DEGREE_PROGRESS_DISTANCE = dipToPx(8);
    
        private static final class ColorConfig {
            private static String HINT_COLOR = "#676767";
            private static String LONG_DEGREE_COLOR = "#000000";
            private static String SHORT_DEGREE_COLOR = "#000000";
        }
    
        private boolean isShowCurrentSpeed = true;
    
        private String titleString;//标题文字
        private String hintString;//内容单位文字
    
        //是否需要标题文字描述等
        private boolean isNeedTitle;
        private boolean isNeedUnit;
        private boolean isNeedDial;
        private boolean isNeedContent;
    
        // 最大角度和最大进度值
        private float kValue;
    
        public ArcProgressBar(Context context) {
            super(context, null);
            initView();
        }
    
        public ArcProgressBar(Context context, AttributeSet attrs) {
            super(context, attrs, 0);
            initCofig(context, attrs);
            initView();
        }
    
        public ArcProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initCofig(context, attrs);
            initView();
        }
    
        /**
         * 初始化布局配置
         */
        private void initCofig(Context context, AttributeSet attrs) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ArcProgressBar);
            int color1 = a.getColor(R.styleable.ArcProgressBar_front_color1, Color.GREEN);
            int color2 = a.getColor(R.styleable.ArcProgressBar_front_color2, color1);
            int color3 = a.getColor(R.styleable.ArcProgressBar_front_color3, color1);
            colors = new int[]{color1, color2, color3, color3};
    
            sweepAngle = a.getInteger(R.styleable.ArcProgressBar_total_engle, 270);
            bgArcWidth = a.getDimension(R.styleable.ArcProgressBar_back_width, dipToPx(2));
            bgArcColor = a.getColor(R.styleable.ArcProgressBar_back_color, Color.BLACK);
            progressWidth = a.getDimension(R.styleable.ArcProgressBar_front_width, dipToPx(10));
            isNeedTitle = a.getBoolean(R.styleable.ArcProgressBar_is_need_title, false);
            isNeedContent = a.getBoolean(R.styleable.ArcProgressBar_is_need_content, false);
            isNeedUnit = a.getBoolean(R.styleable.ArcProgressBar_is_need_unit, false);
            isNeedDial = a.getBoolean(R.styleable.ArcProgressBar_is_need_dial, false);
            hintString = a.getString(R.styleable.ArcProgressBar_string_unit);
            titleString = a.getString(R.styleable.ArcProgressBar_string_title);
            curValues = a.getFloat(R.styleable.ArcProgressBar_current_value, 0);
            maxValues = a.getFloat(R.styleable.ArcProgressBar_max_value, 60);
            aniSpeed = a.getInteger(R.styleable.ArcProgressBar_ani_speed, 1000);
            setCurrentValues(curValues);
            setMaxValues(maxValues);
            a.recycle();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int width = (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
            int height = (int) (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE);
            setMeasuredDimension(width, height);
        }
    
        private void initView() {
            diameter = 3 * getScreenWidth() / 5;
            //弧形的矩阵区域
            bgRect = new RectF();
            bgRect.top = longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE;
            bgRect.left = longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE;
            bgRect.right = diameter + (longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE);
            bgRect.bottom = diameter + (longdegree + progressWidth / 2 + DEGREE_PROGRESS_DISTANCE);
    
            //圆心
            centerX = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE) / 2;
            centerY = (2 * longdegree + progressWidth + diameter + 2 * DEGREE_PROGRESS_DISTANCE) / 2;
    
            //外部刻度线
            degreePaint = new Paint();
            degreePaint.setColor(Color.parseColor(ColorConfig.LONG_DEGREE_COLOR));
    
            //整个弧形
            allArcPaint = new Paint();
            allArcPaint.setAntiAlias(true);
            allArcPaint.setStyle(Paint.Style.STROKE);
            allArcPaint.setStrokeWidth(bgArcWidth);
            allArcPaint.setColor(bgArcColor);
            allArcPaint.setStrokeCap(Paint.Cap.ROUND);
    
            //当前进度的弧形
            progressPaint = new Paint();
            progressPaint.setAntiAlias(true);
            progressPaint.setStyle(Paint.Style.STROKE);
            progressPaint.setStrokeCap(Paint.Cap.ROUND);
            progressPaint.setStrokeWidth(progressWidth);
            progressPaint.setColor(Color.GREEN);
    
            //内容显示文字
            vTextPaint = new Paint();
            vTextPaint.setTextSize(textSize);
            vTextPaint.setColor(Color.BLACK);
            vTextPaint.setTextAlign(Paint.Align.CENTER);
    
            //显示单位文字
            hintPaint = new Paint();
            hintPaint.setTextSize(hintSize);
            hintPaint.setColor(Color.parseColor(ColorConfig.HINT_COLOR));
            hintPaint.setTextAlign(Paint.Align.CENTER);
    
            //显示标题文字
            curSpeedPaint = new Paint();
            curSpeedPaint.setTextSize(curSpeedSize);
            curSpeedPaint.setColor(Color.parseColor(ColorConfig.HINT_COLOR));
            curSpeedPaint.setTextAlign(Paint.Align.CENTER);
    
            //抗锯齿,渐变渲染,矩阵
            mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
            sweepGradient = new SweepGradient(centerX, centerY, colors, null);
            rotateMatrix = new Matrix();
    
        }
    
        @SuppressLint("DefaultLocale")
        @Override
        protected void onDraw(Canvas canvas) {
            //抗锯齿
            canvas.setDrawFilter(mDrawFilter);
    
            if (isNeedDial) {
                //画刻度线
                for (int i = 0; i < 40; i++) {
                    if (i > 15 && i < 25) {
                        canvas.rotate(9, centerX, centerY);
                        continue;
                    }
                    if (i % 5 == 0) {
                        degreePaint.setStrokeWidth(dipToPx(2));
                        degreePaint.setColor(Color.parseColor(ColorConfig.LONG_DEGREE_COLOR));
                        canvas.drawLine(centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE,
                                centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - longdegree, degreePaint);
                    } else {
                        degreePaint.setStrokeWidth(dipToPx(1.4f));
                        degreePaint.setColor(Color.parseColor(ColorConfig.SHORT_DEGREE_COLOR));
                        canvas.drawLine(centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longdegree - shortdegree) / 2,
                                centerX, centerY - diameter / 2 - progressWidth / 2 - DEGREE_PROGRESS_DISTANCE - (longdegree - shortdegree) / 2 - shortdegree, degreePaint);
                    }
                    canvas.rotate(9, centerX, centerY);
                }
            }
    
            //整个弧
            canvas.drawArc(bgRect, startAngle, sweepAngle, false, allArcPaint);
    
            //设置渐变色
            rotateMatrix.setRotate(130, centerX, centerY);
            sweepGradient.setLocalMatrix(rotateMatrix);
            progressPaint.setShader(sweepGradient);
    
            //当前进度
            canvas.drawArc(bgRect, startAngle, currentAngle, false, progressPaint);
    
            if (isNeedContent) {
                canvas.drawText(String.format("%.0f", curValues), centerX, centerY + textSize / 3, vTextPaint);
            }
            if (isNeedUnit) {
                canvas.drawText(hintString, centerX, centerY + 2 * textSize / 3, hintPaint);
            }
            if (isNeedTitle) {
                canvas.drawText(titleString, centerX, centerY - 2 * textSize / 3, curSpeedPaint);
            }
            invalidate();
        }
    
        /**
         * 设置最大值
         *
         * @param maxValues
         */
        public void setMaxValues(float maxValues) {
            this.maxValues = maxValues;
            kValue = sweepAngle / maxValues;
        }
    
        /**
         * 设置动画时长
         *
         * @param aniSpeed
         */
        public void setAniSpeed(int aniSpeed) {
            this.aniSpeed = aniSpeed;
        }
    
        /**
         * 设置当前值
         *
         * @param currentValues
         */
        public void setCurrentValues(float currentValues) {
            if (currentValues > maxValues) {
                currentValues = maxValues;
            }
            if (currentValues < 0) {
                currentValues = 0;
            }
            this.curValues = currentValues;
            lastAngle = currentAngle;
            setAnimation(lastAngle, currentValues * kValue, aniSpeed);
        }
    
        /**
         * 设置整个圆弧宽度
         *
         * @param bgArcWidth
         */
        public void setBgArcWidth(int bgArcWidth) {
            this.bgArcWidth = bgArcWidth;
        }
    
        /**
         * 设置进度宽度
         *
         * @param progressWidth
         */
        public void setProgressWidth(int progressWidth) {
            this.progressWidth = progressWidth;
        }
    
        /**
         * 设置速度文字大小
         *
         * @param textSize
         */
        public void setTextSize(int textSize) {
            this.textSize = textSize;
        }
    
        /**
         * 设置单位文字大小
         *
         * @param hintSize
         */
        public void setHintSize(int hintSize) {
            this.hintSize = hintSize;
        }
    
        /**
         * 设置单位文字
         *
         * @param hintString
         */
        public void setUnit(String hintString) {
            this.hintString = hintString;
            invalidate();
        }
    
        /**
         * 设置直径大小
         *
         * @param diameter
         */
        public void setDiameter(int diameter) {
            this.diameter = dipToPx(diameter);
        }
    
        /**
         * 设置标题
         *
         * @param title
         */
        private void setTitle(String title) {
            this.titleString = title;
        }
    
        /**
         * 设置是否显示标题
         *
         * @param isNeedTitle
         */
        private void setIsNeedTitle(boolean isNeedTitle) {
            this.isNeedTitle = isNeedTitle;
        }
    
        /**
         * 设置是否显示单位文字
         *
         * @param isNeedUnit
         */
        private void setIsNeedUnit(boolean isNeedUnit) {
            this.isNeedUnit = isNeedUnit;
        }
    
        /**
         * 设置是否显示外部刻度盘
         *
         * @param isNeedDial
         */
        private void setIsNeedDial(boolean isNeedDial) {
            this.isNeedDial = isNeedDial;
        }
    
        /**
         * 为进度设置动画
         *
         * @param last
         * @param current
         */
        private void setAnimation(float last, float current, int length) {
            progressAnimator = ValueAnimator.ofFloat(last, current);
            progressAnimator.setDuration(length);
            progressAnimator.setTarget(currentAngle);
            progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    currentAngle = (float) animation.getAnimatedValue();
                    curValues = currentAngle / kValue;
                }
            });
            progressAnimator.start();
        }
    
        /**
         * dip 转换成px
         *
         * @param dip
         * @return
         */
        private int dipToPx(float dip) {
            float density = getContext().getResources().getDisplayMetrics().density;
            return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));
        }
    
        /**
         * 得到屏幕宽度
         *
         * @return
         */
        private int getScreenWidth() {
            WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics displayMetrics = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(displayMetrics);
            return displayMetrics.widthPixels;
        }
    }
    

    attrs.xml

    <declare-styleable name="ArcProgressBar">
            <attr name="back_width" format="dimension" />
            <attr name="back_color" format="color" />
            <attr name="front_color1" format="color" />
            <attr name="front_color2" format="color" />
            <attr name="front_color3" format="color" />
            <attr name="front_width" format="dimension" />
    
            <attr name="current_value" format="float" />
            <attr name="max_value" format="float" />
            <attr name="total_engle" format="integer" />
            <attr name="ani_speed" format="integer" />
            
            <attr name="string_title" format="string" />
            <attr name="string_unit" format="string" />
            <attr name="is_need_title" format="boolean" />
            <attr name="is_need_content" format="boolean" />
            <attr name="is_need_unit" format="boolean" />
            <attr name="is_need_dial" format="boolean" />
    </declare-styleable>
    

    XML引用

            <com.zkzj.android_commer.util.ArcProgressBar
                android:id="@+id/progress_arc"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/iv_head"
                app:back_color="#EE5A5A"
                android:layout_centerInParent="true"
                app:current_value="0"
                app:front_color1="@color/colorAccent"
                app:front_color2="@color/colorPrimary"
                app:front_color3="@color/colorPrimaryDark"
                app:front_width="@dimen/qb_px_4"
                app:is_need_content="true"
                app:is_need_dial="true"
                app:is_need_unit="true"
                app:max_value="100"
                app:string_title="@string/app_name"
                app:string_unit="This is unit"
                app:total_engle="270"
                />
    
    

    Activity调用

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                    //时长
                    mProgressArc.setAniSpeed(3000);
                    //模拟动态进度
                    for (int i = 0; i < 106; i++) {
                        mProgressArc.setCurrentValues(i);
                    }
    
                    }
                });
    
    

    至此,效果就完成了,效果非常的酷炫,大家一起动手试试吧

    文章很短,路还漫长,大家好,我是玖玖君,一个帅气与才华并存的男人,我们下期再见。

    相关文章

      网友评论

          本文标题:自定义进度条(仿汽车时速表)

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