最近有个需求显示进度,尾部还要有一标示,像下边这样
使用自定义View的方式实现,代码如下,很简单注释的很清楚
文章最后我们拓展一下功能,实现一个带动画效果的进度条
package com.example.fwc.allexample.progressbar;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import com.example.fwc.allexample.R;
/**
* Created by fwc on 2016/7/6.
*/
public class CircleProgressBar extends View {
private Context mContext;
private Paint mPaint;
private int mProgress = 0;
private static int MAX_PROGRESS = 100;
/**
* 弧度
*/
private int mAngle;
/**
* 中间的文字
*/
private String mText;
/**
* 外圆颜色
*/
private int outRoundColor;
/**
* 内圆的颜色
*/
private int inRoundColor;
/**
* 线的宽度
*/
private int roundWidth;
private int style;
/**
* 字体颜色
*/
private int textColor;
/**
* 字体大小
*/
private float textSize;
/**
* 字体是否加粗
*/
private boolean isBold;
/**
* 进度条颜色
*/
private int progressBarColor;
public CircleProgressBar(Context context) {
this(context, null);
}
public CircleProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
init(attrs);
}
@TargetApi(21)
public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mContext = context;
init(attrs);
}
/**
* 解析自定义属性
*
* @param attrs
*/
public void init(AttributeSet attrs) {
mPaint = new Paint();
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar);
outRoundColor = typedArray.getColor(R.styleable.CircleProgressBar_outCircleColor, getResources().getColor(R.color.colorPrimary));
inRoundColor = typedArray.getColor(R.styleable.CircleProgressBar_inCircleColor, getResources().getColor(R.color.colorPrimaryDark));
progressBarColor = typedArray.getColor(R.styleable.CircleProgressBar_progressColor, getResources().getColor(R.color.colorAccent));
isBold = typedArray.getBoolean(R.styleable.CircleProgressBar_textBold, false);
textColor = typedArray.getColor(R.styleable.CircleProgressBar_textColor, Color.BLACK);
roundWidth = typedArray.getDimensionPixelOffset(R.styleable.CircleProgressBar_lineWidth, 20);
typedArray.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
/**
* 画外圆
*/
super.onDraw(canvas);
int center = getWidth() / 2; //圆心
int radius = (center - roundWidth / 2); //半径
mPaint.setColor(outRoundColor); //外圆颜色
mPaint.setStrokeWidth(roundWidth); //线的宽度
mPaint.setStyle(Paint.Style.STROKE); //空心圆
mPaint.setAntiAlias(true); //消除锯齿
canvas.drawCircle(center, center, radius, mPaint);
//内圆
mPaint.setColor(inRoundColor);
radius = radius - roundWidth;
canvas.drawCircle(center, center, radius, mPaint);
//画进度是一个弧线
mPaint.setColor(progressBarColor);
RectF rectF = new RectF(center - radius, center - radius, center + radius, center + radius);//圆弧范围的外接矩形
canvas.drawArc(rectF, -90, mAngle, false, mPaint);
canvas.save(); //平移画布之前保存之前画的
//画进度终点的小球,旋转画布的方式实现
mPaint.setStyle(Paint.Style.FILL);
//将画布坐标原点移动至圆心
canvas.translate(center, center);
//旋转和进度相同的角度,因为进度是从-90度开始的所以-90度
canvas.rotate(mAngle - 90);
//同理从圆心出发直接将原点平移至要画小球的位置
canvas.translate(radius, 0);
canvas.drawCircle(0, 0, roundWidth, mPaint);
//画完之后恢复画布坐标
canvas.restore();
//画文字将坐标平移至圆心
canvas.translate(center, center);
mPaint.setStrokeWidth(0);
mPaint.setColor(textColor);
if (isBold) {
//字体加粗
mPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
if (TextUtils.isEmpty(mText)) {
mText = mProgress + "%";
}
//动态设置文字长为圆半径,计算字体大小
float textLength = mText.length();
textSize = radius / textLength;
mPaint.setTextSize(textSize);
//将文字画到中间
float textWidth = mPaint.measureText(mText);
canvas.drawText(mText, -textWidth / 2, textSize / 2, mPaint);
}
public int getmProgress() {
return mProgress;
}
/**
* 设置进度
*
* @return
*/
public void setmProgress(int p) {
if (p > MAX_PROGRESS) {
mProgress = MAX_PROGRESS;
mAngle = 360;
} else {
mProgress = p;
mAngle = 360 * p / MAX_PROGRESS;
}
}
public String getmText() {
return mText;
}
/**
* 设置文本
*
* @param mText
*/
public void setmText(String mText) {
this.mText = mText;
}
/**
* 设置带动画的进度
* @param p
*/
public void setAnimProgress(int p) {
if (p > MAX_PROGRESS) {
mProgress = MAX_PROGRESS;
} else {
mProgress = p;
}
//设置属性动画
ValueAnimator valueAnimator = new ValueAnimator().ofInt(0, p);
//动画从快到慢
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(3000);
//监听值的变化
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentV = (Integer) animation.getAnimatedValue();
Log.e("fwc", "current" + currentV);
mAngle = 360 * currentV / MAX_PROGRESS;
mText = currentV + "%";
invalidate();
}
});
valueAnimator.start();
}
}
自定义属性
<declare-styleable name="CircleProgressBar">
<attr name="outCircleColor" format="color">attr>
<attr name="inCircleColor" format="color">attr>
<attr name="progressColor" format="color">attr>
<attr name="textColor" format="color">attr>
<attr name="textBold" format="boolean">attr>
<attr name="lineWidth" format="dimension">attr>
declare-styleable>
布局文件中使用
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:my="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.fwc.allexample.progressbar.ProgressActivtiy">
<com.example.fwc.allexample.progressbar.CircleProgressBar
android:id="@+id/progress_bar"
android:layout_centerInParent="true"
android:layout_width="150dp"
android:layout_height="150dp"
my:inCircleColor="#DCDCDC"
my:outCircleColor="#F0F0F0"
my:progressColor="#50CE7B"
my:textBold="true"
my:textColor="#50CE7B"
my:lineWidth="5dp"
/>
RelativeLayout>
activity中设置进度,显示文字
package com.example.fwc.allexample.progressbar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.example.fwc.allexample.R;
public class ProgressActivtiy extends AppCompatActivity {
CircleProgressBar circleProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progress_activtiy);
circleProgressBar = (CircleProgressBar)findViewById(R.id.progress_bar);
circleProgressBar.setProgress(65);
circleProgressBar.setmText(circleProgressBar.getProgress()+"%");
}
}
拓展也很简单,加一个setAnimProgress(int p)设置动画效果:
/**
* 设置带动画的进度
* @param p
*/
public void setAnimProgress(int p) {
if (p > MAX_PROGRESS) {
mProgress = MAX_PROGRESS;
} else {
mProgress = p;
}
//设置属性动画
ValueAnimator valueAnimator = new ValueAnimator().ofInt(0, p);
//动画从快到慢
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(3000);
//监听值的变化
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentV = (Integer) animation.getAnimatedValue();
Log.e("fwc", "current" + currentV);
mAngle = 360 * currentV / MAX_PROGRESS;
mText = currentV + "%";
invalidate();
}
});
valueAnimator.start();
}
在activity中调用这个方法
circleProgressBar.setAnimProgress(65);