先上效果图:
Demo地址: https://github.com/liys666666/LiysProgressView
以下代码直接复制即可使用, 碰到类似样式的, 可以根据自己需求修改.
①. 在arrts.xml添加对应属性.
②. 把源码复制过去即可使用.
1. 圆弧进度条 ArcProgressView
属性:
<!-- 圆弧进度条 -->
<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
属性:
<!-- 线性进度条(带文字) -->
<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
属性
<!-- 水平进度条 (带文字)-->
<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
属性:
<!-- 水平进度条(不带文字)-->
<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
属性:
<!-- 水波 进度条 -->
<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();
}
}