最近开发写了两个简单的进度条控件,分享一下
2017-09-13 17:18
435 查看
先看看效果图
源码在下面,自取
源码在下面,自取
public class BatteryContinueView extends View { private Paint allArcPaint;//底部圆的画笔 private Paint innerrPaint;//底部圆的画笔 private Paint progressPaint; private Paint vTextPaint; private Paint curSpeedPaint; private Paint mPaintPointer; private PaintFlagsDrawFilter mDrawFilter; private int maxValues = 100;//最大值 private int currentValues = 100;//当前值 private int endvalues = 100;//当前值 private int bgArcWidth = dipToPx(5);//背景弧的宽度 private float textSize = UIUtils.sp2px(22); private float curSpeedSize = UIUtils.sp2px(16); private String hintColor = "#0B9AE8"; private String bgArcColor = "#E7E7E7";//圆弧背景颜色 private String titleString = "续航里程"; private int mSize; // 最终的大小 private int mRadus; private float mCenterX, mCenterY; // 圆心坐标 RectF bgRectf;//最外层的矩形 RectF innerRectf;//内存的矩形 private float startangle = 135f; private float sweepAngle = 270; private int mSecondeRedus; public BatteryContinueView(Context context) { this(context, null); } public BatteryContinueView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BatteryContinueView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } @SuppressLint("DrawAllocation") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int realWidth = startMeasure(widthMeasureSpec); int realHeight = startMeasure(heightMeasureSpec); /** * 因为是以正方形为基础 */ mSize = Math.min(realHeight, realWidth); setMeasuredDimension(mSize, mSize); mCenterX = mCenterY = getMeasuredWidth() / 2f; mRadus = getMeasuredWidth() / 2 - bgArcWidth / 2; int scaleArcRadius = mSize / 2 - bgArcWidth / 2; bgRectf = new RectF(getPaddingLeft() + bgArcWidth / 2, getPaddingTop() + bgArcWidth / 2, getMeasuredWidth() - bgArcWidth / 2, getMeasuredHeight() - bgArcWidth / 2); Shader mShader = new LinearGradient(0, getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight(), new int[]{Color.parseColor("#4F8DFE"), Color.parseColor("#27C4FD")}, null, Shader.TileMode.REPEAT); //新建一个线性渐变,前两个参数是渐变开始的点坐标,第三四个参数是渐变结束的点的坐标 // 连接这2个点就拉出一条渐变线了, // 玩过PS的都懂。然后那个数组是渐变的颜色。下一个参数是渐变颜色的分布, // 如果为空,每个颜色就是均匀分布的。最后是模式,这里设置的是循环渐变 progressPaint.setShader(mShader); mSecondeRedus = mRadus - dp2px(10); //画内部圆弧 innerRectf = new RectF(getPaddingLeft() + bgArcWidth / 2 + dp2px(10), getPaddingTop() + bgArcWidth / 2 + dp2px(10), getMeasuredWidth() - bgArcWidth / 2 - dp2px(10), getMeasuredHeight() - bgArcWidth / 2 - dp2px(10)); } /** * 测量大小 */ private int startMeasure(int whSpec) { int result = 0; int size = MeasureSpec.getSize(whSpec); int mode = MeasureSpec.getMode(whSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { result = dp2px(220); } return result; } private void initPaint() { path = new Path(); //整个弧形 allArcPaint = new Paint(); allArcPaint.setAntiAlias(true); allArcPaint.setStyle(Paint.Style.STROKE); allArcPaint.setStrokeWidth(bgArcWidth); allArcPaint.setColor(Color.parseColor(bgArcColor)); allArcPaint.setStrokeCap(Paint.Cap.ROUND); //内部的圆 innerrPaint = new Paint(); innerrPaint.setAntiAlias(true); innerrPaint.setStyle(Paint.Style.STROKE); innerrPaint.setStrokeWidth(UIUtils.dp2px(2)); innerrPaint.setColor(Color.parseColor("#5DAEFE")); innerrPaint.setStrokeCap(Paint.Cap.ROUND); //当前进度的弧形 progressPaint = new Paint(); progressPaint.setAntiAlias(true); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeCap(Paint.Cap.ROUND); progressPaint.setStrokeWidth(bgArcWidth); progressPaint.setColor(Color.RED); //内容显示文字 vTextPaint = new Paint(); vTextPaint.setTextSize(textSize); vTextPaint.setColor(Color.parseColor("#0B9AE8")); vTextPaint.setTextAlign(Paint.Align.CENTER); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD); vTextPaint.setTypeface(font); //显示标题文字 curSpeedPaint = new Paint(); curSpeedPaint.setTextSize(curSpeedSize); curSpeedPaint.setColor(Color.parseColor(hintColor)); curSpeedPaint.setTextAlign(Paint.Align.CENTER); linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); linePaint.setDither(true); linePaint.setColor(Color.parseColor("#E7E7E7")); mPaintPointer = new Paint(); mPaintPointer.setAntiAlias(true); mPaintPointer.setStrokeWidth(3); mPaintPointer.setStyle(Paint.Style.FILL); mPaintPointer.setColor(Color.parseColor("#2CBDFD")); mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); } //画外边缘线的画笔 private Paint linePaint; /** * 实现画刻度线的功能 */ private void drawLine(final Canvas canvas) { // 保存之前的画布状态 canvas.save(); // 移动画布,实际上是改变坐标系的位置 canvas.translate(mCenterX, mCenterX); canvas.rotate(45); // 设置画笔的宽度(线的粗细) linePaint.setStrokeWidth(UIUtils.sp2px(1)); // 累计叠加的角度 float c = 0; float sweepAngle = 270; float a = sweepAngle / 45; for (int i = 0; i <= 45; i++) { double p = c / (double) sweepAngle; canvas.drawLine(0, mSecondeRedus - dp2px(10), 0, mSecondeRedus - dp2px(2), linePaint); // 画过的角度进行叠加 c += a; canvas.rotate(a); } // 恢复画布状态。 canvas.restore(); } @Override protected void onDraw(Canvas canvas) { //抗锯齿 canvas.setDrawFilter(mDrawFilter); //整个弧 canvas.drawArc(bgRectf, startangle, sweepAngle, false, allArcPaint); //画内部圆弧 canvas.drawArc(innerRectf, startangle, sweepAngle, false, innerrPaint); drawLine(canvas); //画进度圆弧 int percent = currentValues * (270) / maxValues; canvas.drawArc(bgRectf, startangle, percent, false, progressPaint); //写中间进度 canvas.drawText(currentValues + "km", mCenterX, getMeasuredHeight() - textSize * 3 / 2, vTextPaint); //写title canvas.drawText(titleString, mCenterX, getMeasuredHeight() - textSize / 2, curSpeedPaint); drawPointer(canvas); } private int mPotinterRaduis; private Path path; /** * 绘制指针 */ private void drawPointer(Canvas canvas) { mPotinterRaduis = mRadus / 8; float initAngle = getAngleFromResult(currentValues); path.reset(); float[] point1 = getCoordinatePoint(mPotinterRaduis / 2, initAngle + 90); path.moveTo(point1[0], point1[1]); float[] point2 = getCoordinatePoint(mPotinterRaduis / 2, initAngle - 90); path.lineTo(point2[0], point2[1]); float[] point3 = getCoordinatePoint(mRadus / 3, initAngle); path.lineTo(point3[0], point3[1]); path.close(); canvas.drawPath(path, mPaintPointer); // 绘制三角形指针底部的圆弧效果 canvas.drawCircle((point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2, mPotinterRaduis * 3 / 4, mPaintPointer); } private int mMin = 0; // 最小值 /** * 通过数值得到角度位置 */ private float getAngleFromResult(float result) { if (result > maxValues) return currentValues; return sweepAngle * (result - mMin) / (maxValues - mMin) + startangle; } /** * 依圆心坐标,半径,扇形角度,计算出扇形终射线与圆弧交叉点的xy坐标 */ public float[] getCoordinatePoint(int radius, float angle) { float[] point = new float[2]; double arcAngle = Math.toRadians(angle); //将角度转换为弧度 if (angle < 90) { point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius); point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius); } else if (angle == 90) { point[0] = mCenterX; point[1] = mCenterY + radius; } else if (angle > 90 && angle < 180) { arcAngle = Math.PI * (180 - angle) / 180.0; point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius); point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius); } else if (angle == 180) { point[0] = mCenterX - radius; point[1] = mCenterY; } else if (angle > 180 && angle < 270) { arcAngle = Math.PI * (angle - 180) / 180.0; point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius); point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius); } else if (angle == 270) { point[0] = mCenterX; point[1] = mCenterY - radius; } else { arcAngle = Math.PI * (360 - angle) / 180.0; point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius); point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius); } return point; } /** * 设置当前值 * * @param currentValues */ public void setCurrentValues(int currentValues) { if (currentValues > maxValues) { currentValues = maxValues; } if (currentValues < 0) { currentValues = 0; } setAnimator(currentValues); } ValueAnimator valueAnimator; private int animatorDuration; private void setAnimator(final int percent) { //根据变化的幅度来调整动画时长 animatorDuration = (int) Math.abs(percent - endvalues) * 40; // 在这里我们用到了ValueAnimator,ValuAnimator本质上就是通过设置一个起始值和结束值,来取到一个从起始值到结束值的一个逐渐增长的Animation值。在draw方法中使用这个值并且不断的重绘,就能达到一种动画效果。 valueAnimator = ValueAnimator.ofInt(currentValues, percent).setDuration(animatorDuration); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //把获取到的 currentValues = (int) animation.getAnimatedValue(); invalidate(); } }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); currentValues = (int) percent; } }); valueAnimator.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)); } }
public class ColorArcProgressBar extends View { private Paint allArcPaint;//底部圆的画笔 private Paint progressPaint; private Paint vTextPaint; private Paint curSpeedPaint; private PaintFlagsDrawFilter mDrawFilter; private int maxValues = 100;//最大值 private int currentValues = 100;//当前值 private int endvalues = 100;//当前值 private int bgArcWidth = dipToPx(15);//背景弧的宽度 private float textSize = UIUtils.sp2px(30); private float curSpeedSize = UIUtils.sp2px(16); private String hintColor = "#0B9AE8"; private String bgArcColor = "#E7E7E7";//圆弧背景颜色 private String titleString = "剩余电量"; private int mSize; // 最终的大小 private int mRadus; private float mCenterX, mCenterY; // 圆心坐标 RectF bgRectf; private float startangle = 180f; public ColorArcProgressBar(Context context) { this(context, null); } public ColorArcProgressBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ColorArcProgressBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } @SuppressLint("DrawAllocation") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int realWidth = startMeasure(widthMeasureSpec); int realHeight = startMeasure(heightMeasureSpec); /** * 因为是以正方形为基础 */ mSize = Math.min(realHeight, realWidth); setMeasuredDimension(mSize, mSize); mCenterX = mCenterY = getMeasuredWidth() / 2f; mRadus = getMeasuredWidth() / 2 - bgArcWidth / 2; int scaleArcRadius = mSize / 2 - bgArcWidth / 2; bgRectf = new RectF(getPaddingLeft() + bgArcWidth / 2, getPaddingTop() + bgArcWidth / 2, getMeasuredWidth() - bgArcWidth / 2, getMeasuredHeight() - bgArcWidth / 2); Shader mShader = new LinearGradient(0, getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight(), new int[]{Color.parseColor("#4F8DFE"), Color.parseColor("#27C4FD")}, null, Shader.TileMode.REPEAT); //新建一个线性渐变,前两个参数是渐变开始的点坐标,第三四个参数是渐变结束的点的坐标 // 连接这2个点就拉出一条渐变线了, // 玩过PS的都懂。然后那个数组是渐变的颜色。下一个参数是渐变颜色的分布, // 如果为空,每个颜色就是均匀分布的。最后是模式,这里设置的是循环渐变 progressPaint.setShader(mShader); } /** * 测量大小 */ private int startMeasure(int whSpec) { int result = 0; int size = MeasureSpec.getSize(whSpec); int mode = MeasureSpec.getMode(whSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { result = UIUtils.dp2px(220); } return result; } private void initPaint() { //整个弧形 allArcPaint = new Paint(); allArcPaint.setAntiAlias(true); allArcPaint.setStyle(Paint.Style.STROKE); allArcPaint.setStrokeWidth(bgArcWidth); allArcPaint.setColor(Color.parseColor(bgArcColor)); allArcPaint.setStrokeCap(Paint.Cap.ROUND); //当前进度的弧形 progressPaint = new Paint(); progressPaint.setAntiAlias(true); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeCap(Paint.Cap.ROUND); progressPaint.setStrokeWidth(bgArcWidth); progressPaint.setColor(Color.RED); //内容显示文字 vTextPaint = new Paint(); vTextPaint.setTextSize(textSize); vTextPaint.setColor(Color.parseColor("#0085D0")); vTextPaint.setTextAlign(Paint.Align.CENTER); Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD); vTextPaint.setTypeface(font); //显示标题文字 curSpeedPaint = new Paint(); curSpeedPaint.setTextSize(curSpeedSize); curSpeedPaint.setColor(Color.parseColor(hintColor)); curSpeedPaint.setTextAlign(Paint.Align.CENTER); mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); } @Override protected void onDraw(Canvas canvas) { //抗锯齿 canvas.setDrawFilter(mDrawFilter); //整个弧 canvas.drawCircle(mCenterX, mCenterY, mRadus, allArcPaint); //画进度圆弧 int percent = currentValues * (-360) / maxValues; canvas.drawArc(bgRectf, startangle, percent, false, progressPaint); //写中间进度 canvas.drawText(currentValues + "%", mCenterX, mCenterY + textSize * 2 / 3, vTextPaint); //写title canvas.drawText(titleString, mCenterX, mCenterY - textSize / 2, curSpeedPaint); } /** * 设置当前值 * * @param currentValues */ public void setCurrentValues(int currentValues) { if (currentValues > maxValues) { currentValues = maxValues; } if (currentValues < 0) { currentValues = 0; } setAnimator(currentValues); } ValueAnimator valueAnimator; private int animatorDuration; private void setAnimator(final int percent) { //根据变化的幅度来调整动画时长 animatorDuration = (int) Math.abs(percent - endvalues) * 40; // 在这里我们用到了ValueAnimator,ValuAnimator本质上就是通过设置一个起始值和结束值,来取到一个从起始值到结束值的一个逐渐增长的Animation值。在draw方法中使用这个值并且不断的重绘,就能达到一种动画效果。 valueAnimator = ValueAnimator.ofInt(currentValues, percent).setDuration(animatorDuration); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //把获取到的 currentValues = (int) animation.getAnimatedValue(); invalidate(); } }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); currentValues = (int) percent; } }); valueAnimator.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)); } }
相关文章推荐
- 分享自己写的两个控件,适用于用html + js开发App
- 分享一下“流程开发时如何根据发起人的部门来确定某个选人控件的范围”
- 给大家分享一下最近开发遇到的一些坑
- 分享两个实用的ASP.NET开发技巧——使用WebMethod实现ajax和控件的ClientIDMode属性
- 蛙蛙推荐:最近开发一个小型的OA,把常用代码和大家分享一下先
- OCX控件的简单开发实例
- ios开发两个简单的错误提示和原因
- 【按住你的心】——Android开发CheckBox&RadioButton控件的简单使用
- 第一章 .Net 控件开发(WebForm) 开发简单自定义控件(2) 控件属性的申明
- 最近微信上很火的小游戏【壹秒】android版——开发分享
- iOS开发UI篇—Date Picker和UITool Bar控件简单介绍
- iOS开发UI篇—Date Picker和UITool Bar控件简单介绍
- 分享一下最近收集的hadoop视频资料
- iOS开发UI基础—18UITableview控件简单介绍
- 使用objectdatasource结合数据绑定控件进行简单三层架构的开发
- iOS开发UI篇—UIPickerView控件简单介绍
- XE4控件开发源码 最简单的例子
- 分享一个获取控件 id 较简单的方法
- iOS开发UI篇—UIPickerView控件简单介绍
- asp.net控件开发基础(5) ----------简单介绍自定义控件简单属性和复杂属性