<declare-styleable name="WaterProgressView"> <attr name="circle_color" format="color"/><!--圆的颜色--> <attr name="progress_color" format="color"/><!--进度的颜色--> <attr name="text_color" format="color"/><!--文字的颜色--> <attr name="text_size" format="dimension"/><!--文字大小--> <attr name="ripple_topheight" format="dimension"/><!--水页涟漪最大高度--> </declare-styleable>
public class WaterProgressView extends ProgressBar {
//默认圆的背景色
public static final int DEFAULT_CIRCLE_COLOR = 0xff00cccc;
//默认进度的颜色
public static final int DEFAULT_PROGRESS_COLOR = 0xff00CC66;
//默认文字的颜色
public static final int DEFAULT_TEXT_COLOR = 0xffffffff;
//默认文字的大小
public static final int DEFAULT_TEXT_SIZE = 18;
//默认的波峰最高点
public static final int DEFAULT_RIPPLE_TOPHEIGHT = 10;
private Context mContext;
private Canvas mPaintCanvas;
private Bitmap mBitmap;
//画圆的画笔
private Paint mCirclePaint;
//画圆的画笔的颜色
private int mCircleColor;
//画进度的画笔
private Paint mProgressPaint;
//画进度的画笔的颜色
private int mProgressColor ;
//画进度的path
private Path mProgressPath;
//贝塞尔曲线波峰最大值
private int mRippleTop = 10;
//进度文字的画笔
private Paint mTextPaint;
//进度文字的颜色
private int mTextColor;
private int mTextSize = 18;
//目标进度,也就是双击时处理任务的进度,会影响曲线的振幅
private int mTargetProgress = 50;
//监听双击和单击事件
private GestureDetector mGestureDetector;
}
private void getAttrValue(AttributeSet attrs) {
TypedArray ta = mContext.obtainStyledAttributes(attrs, R.styleable.WaterProgressView);
mCircleColor = ta.getColor(R.styleable.WaterProgressView_circle_color,DEFAULT_CIRCLE_COLOR);
mProgressColor = ta.getColor(R.styleable.WaterProgressView_progress_color,DEFAULT_PROGRESS_COLOR);
mTextColor = ta.getColor(R.styleable.WaterProgressView_text_color,DEFAULT_TEXT_COLOR);
mTextSize = (int) ta.getDimension(R.styleable.WaterProgressView_text_size, DesityUtils.sp2px(mContext,DEFAULT_TEXT_SIZE));
mRippleTop = (int)ta.getDimension(R.styleable.WaterProgressView_ripple_topheight,DesityUtils.dp2px(mContext,DEFAULT_RIPPLE_TOPHEIGHT));
ta.recycle();
}
//当new该类时调用此构造函数
public WaterProgressView(Context context) {
this(context,null);
}
//当xml文件中定义该自定义View时调用此构造函数
public WaterProgressView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public WaterProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
getAttrValue(attrs);
//初始化画笔的相关属性
initPaint();
mProgressPath = new Path();
}
private void initPaint() {
//初始化画圆的paint
mCirclePaint = new Paint();
mCirclePaint.setColor(mCircleColor);
mCirclePaint.setStyle(Paint.Style.FILL);
mCirclePaint.setAntiAlias(true);
mCirclePaint.setDither(true);
//初始化画进度的paint
mProgressPaint = new Paint();
mProgressPaint.setColor(mProgressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setDither(true);
mProgressPaint.setStyle(Paint.Style.FILL);
//其实mProgressPaint画的也是矩形,当设置xfermode为PorterDuff.Mode.SRC_IN后则显示的为圆与进度矩形的交集,则为半圆
mProgressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//初始化画进度文字的画笔
mTextPaint = new Paint();
mTextPaint.setColor(mTextColor);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setAntiAlias(true);
mTextPaint.setDither(true);
mTextPaint.setTextSize(mTextSize);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//使用时,需要明确定义该View的尺寸,即用测量模式为MeasureSpec.EXACTLY
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width,height);
//初始化Bitmap,让所有的drawCircle,drawPath,drawText都draw在该bitmap所在的canvas上,然后再将该bitmap 画在onDraw方法的canvas上,
//所以此bitmap的width,height需要减去left,top,right,bottom的padding
mBitmap = Bitmap.createBitmap(width-getPaddingLeft()-getPaddingRight(),height- getPaddingTop()-getPaddingBottom(), Bitmap.Config.ARGB_8888);
mPaintCanvas = new Canvas(mBitmap);
}
float ratio = getProgress()*1.0f/getMax();
int rightTop = (int) ((1-ratio)*height); mProgressPath.moveTo(width,rightTop); mProgressPath.lineTo(width,height); mProgressPath.lineTo(0,height); mProgressPath.lineTo(0,rightTop);
int count = (int) Math.ceil(width*1.0f/(10 *4));
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(10,10,2* 10,0);
mProgressPath.rQuadTo(10,-10,2* 10,0);
}
mProgressPath.close();
mPaintCanvas.drawPath(mProgressPath,mProgressPaint);
float top = (mTargetProgress-getProgress())*1.0f/mTargetProgress* mRippleTop;
float top = (mTargetProgress-getProgress())*1.0f/mTargetProgress* mRippleTop;
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(mRippleTop,top,2* mRippleTop,0);
mProgressPath.rQuadTo(mRippleTop,-top,2* mRippleTop,0);
}
/**
* 实现双击动画
*/
private void startDoubleTapAnimation() {
setProgress(0);
doubleTapHandler.postDelayed(doubleTapRunnable,60);
}
private Handler doubleTapHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
//双击处理线程,隔60ms发送一次数据
private Runnable doubleTapRunnable = new Runnable() {
@Override
public void run() {
if(getProgress() < mTargetProgress) {
invalidate();
setProgress(getProgress()+1);
doubleTapHandler.postDelayed(doubleTapRunnable,60);
} else {
doubleTapHandler.removeCallbacks(doubleTapRunnable);
}
}
};
private void startSingleTapAnimation() {
isSingleTapAnimation = true;
singleTapHandler.postDelayed(singleTapRunnable,200);
}
private Handler singleTapHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
//单击处理线程,隔200ms发送一次数据
private Runnable singleTapRunnable = new Runnable() {
@Override
public void run() {
if(mSingleTapAnimationCount > 0) {
invalidate();
mSingleTapAnimationCount--;
singleTapHandler.postDelayed(singleTapRunnable,200);
} else {
singleTapHandler.removeCallbacks(singleTapRunnable);
//是否正在进行单击动画
isSingleTapAnimation = false;
//重置单击动画运行次数为50次
mSingleTapAnimationCount = 50;
}
}
};
//画进度
mProgressPath.reset();
//从右上边开始draw path
int rightTop = (int) ((1-ratio)*height);
mProgressPath.moveTo(width,rightTop);
mProgressPath.lineTo(width,height);
mProgressPath.lineTo(0,height);
mProgressPath.lineTo(0,rightTop);
//画贝塞尔曲线,形成波浪线
int count = (int) Math.ceil(width*1.0f/(mRippleTop *4));
//不是单击animation状态
if(!isSingleTapAnimation&&getProgress()>0) {
float top = (mTargetProgress-getProgress())*1.0f/mTargetProgress* mRippleTop;
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(mRippleTop,-top,2* mRippleTop,0);
mProgressPath.rQuadTo(mRippleTop,top,2* mRippleTop,0);
}
} else {
//单击animation状态,为了将效果放大,将mRippleTop放大2倍
//同时偶数时曲线走向如图所示,奇数时则曲线刚好相反
float top = (mSingleTapAnimationCount*1.0f/50)*10;
//奇偶数时曲线切换
if(mSingleTapAnimationCount%2==0) {
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(mRippleTop *2,top*2,2* mRippleTop,0);
mProgressPath.rQuadTo(mRippleTop *2,-top*2,2* mRippleTop,0);
}
} else {
for(int i=0; i<count; i++) {
mProgressPath.rQuadTo(mRippleTop *2,-top*2,2* mRippleTop,0);
mProgressPath.rQuadTo(mRippleTop *2,top*2,2* mRippleTop,0);
}
}
}
mProgressPath.close();
mPaintCanvas.drawPath(mProgressPath,mProgressPaint);
//自定义bitmap的宽和高 int width = getWidth()-getPaddingLeft()-getPaddingRight(); int height = getHeight()-getPaddingTop()-getPaddingBottom(); //画圆 mPaintCanvas.drawCircle(width/2,height/2,height/2,mCirclePaint);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics(); //因为ascent在baseline之上,所以ascent为负数。descent+ascent为负数,所以是减而不是加 float baseLine = height*1.0f/2 - (metrics.descent+metrics.ascent)/2;
//画进度文字 String text = ((int)(ratio*100))+"%"; //获得文字的宽度 float textWidth = mTextPaint.measureText(text); Paint.FontMetrics metrics = mTextPaint.getFontMetrics(); //descent+ascent为负数,所以是减而不是加 float baseLine = height*1.0f/2 - (metrics.descent+metrics.ascent)/2; mPaintCanvas.drawText(text,width/2-textWidth/2,baseLine,mTextPaint);
canvas.translate(getPaddingLeft(),getPaddingTop()); canvas.drawBitmap(mBitmap,0,0,null);
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有