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

第一步 :自定义view

/**

  • 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
    <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" />

第二步 :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);
            }

            }
        });

最后,文章很短,路还漫长,希望大伙喜欢这篇文章,我们下期再见。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值