计步器View 发表于 2016-10-27 | 分类于 自定义view | 不会自定义view的android程序员不是一个好设计,看了QQ运动的的计步view,瞬间萌生了动手仿一个的想法,只要有思路,代码很简单1.绘背景圆弧2.绘计步圆弧3.绘步数4.绘描述文字6.设置步数5:加动画 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249/** * Created by zhangfeng on 2016/10/26. * 仿计步view */public class StepView extends View { /** * 画笔 */ private Paint paint; /** * 背景圆弧所对应的角度 */ private float arcAngle = 270; /** * 圆弧起点角度 */ private float startlAngle = 135; /** * 圆弧画笔宽度 */ private float paintWidth = 35f; /** * 当前所走步数 */ private int currentStep; /** * 当前所走步数文字大小 */ private float stepTextSize = dipToPx(50); /** * 描述文字 */ private String strText = "步数"; /** * 描述文字大小 */ private int describeTextSize = dipToPx(20); /** * 当前所走步数对应的弧度 */ private float currentStepArc; /** * 设置滚动的速度 */ private int aniSpeed = 3000; public StepView(Context context) { super(context); init(); } public StepView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public StepView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { paint = new Paint(); /** * 填充样式 * Style.STROKE: 扫边 * Style.FILL: 填充 * FILL_AND_STROKE: 填充加扫边 */ paint.setStyle(Paint.Style.STROKE); /** * 抗锯齿 */ paint.setAntiAlias(true); /** * 画笔宽度 */ paint.setStrokeWidth(paintWidth); /** * 画笔的样式 Paint.Cap.Round: 圆形 * Cap.SQUARE: 方形 */ paint.setStrokeCap(Paint.Cap.ROUND); /** * 结合处为圆弧 */ paint.setStrokeJoin(Paint.Join.ROUND); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); /** * 中心点X */ float centerX = getWidth() / 2; /** * 绘制圆弧所显示的区域 * 参数1: 矩形左边距 * 参数2: 矩形上边距 * 参数3: 矩形右边距 * 参数4: 矩形下边距 */ RectF rectF = new RectF(paintWidth + 100, paintWidth + 100, centerX * 2 - paintWidth - 100, centerX * 2 - paintWidth - 100); drawBlueArc(canvas, rectF); drawRedArc(canvas, rectF); drawStepNumber(canvas); drawTipText(canvas); } /** * 绘制蓝色圆弧 * * @param canvas * @param rectF */ private void drawBlueArc(Canvas canvas, RectF rectF) { paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.MAGENTA); paint.setStrokeWidth(paintWidth); /** * 绘制圆弧 * 参数1: 圆弧所在的椭圆对象 * 参数2: 圆弧的起始角度 * 参数3: 圆弧的角度 * 参数4: 是否显示半径连线,true表示显示圆弧与圆心的半径连线,false表示不显示 * 参数5: 画笔 * 如果需绘制270度的圆弧(以本demo为例),圆弧起止点的角度=(360-270)+45 圆弧的绘制方向为顺时针,0度为X轴正方向 */ canvas.drawArc(rectF, startlAngle, arcAngle, false, paint); } /** * 绘制红色圆弧 * * @param canvas * @param rectF */ private void drawRedArc(Canvas canvas, RectF rectF) { paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.YELLOW); paint.setStrokeWidth(paintWidth); canvas.drawArc(rectF, startlAngle, currentStepArc, false, paint); } /** * 绘制当前所走步数 * * @param canvas */ private void drawStepNumber(Canvas canvas) { paint.setStyle(Paint.Style.FILL); paint.setStrokeWidth(10); paint.setColor(Color.WHITE); paint.setTextSize(stepTextSize); Rect rect = new Rect(); paint.getTextBounds(currentStep + "", 0, String.valueOf(currentStep).length(), rect); canvas.drawText(currentStep + "", getWidth() / 2 - rect.width() / 2, getWidth() / 2 + rect.height() / 2, paint); } /** * 绘制描述文字 * * @param canvas */ private void drawTipText(Canvas canvas) { paint.setStyle(Paint.Style.FILL); paint.setStrokeWidth(10); paint.setColor(Color.GRAY); paint.setTextSize(describeTextSize); Rect rect = new Rect(); paint.getTextBounds(strText, 0, strText.length(), rect); canvas.drawText(strText, getWidth() / 2 - rect.width() / 2, getWidth() / 2 + rect.height() + dipToPx(40), paint); } /** * 设置当前所走步数及计划所走步数 * * @param totalStepValue * @param currentStepValue */ public void setCurrentStep(int currentStepValue, int totalStepValue) { currentStep = currentStepValue; if (currentStepValue > totalStepValue) { currentStepValue = totalStepValue; } /** * 将所走步数转化成弧度 * 算法 :(当前所走步数/总步数)*总弧长 */ currentStepArc = ((float) currentStepValue / (float) totalStepValue) * arcAngle; setAinmation(0, currentStepArc, aniSpeed); } /** * 当前走步数加载动画 * * @param last * @param current * @param length */ private void setAinmation(float last, float current, int length) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(last, current); valueAnimator.setDuration(length); valueAnimator.setTarget(currentStepArc); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { currentStepArc = (float) animation.getAnimatedValue(); invalidate(); } }); valueAnimator.start(); } /** * 设置文本大小 * * @param num */ public void setTextSize(int num) { String s = String.valueOf(num); int length = s.length(); if (length <= 4) { stepTextSize = dipToPx(50); } else if (length > 4 && length <= 6) { stepTextSize = dipToPx(40); } else if (length > 6 && length <= 8) { stepTextSize = dipToPx(30); } else if (length > 8) { stepTextSize = dipToPx(25); } } /** * dp 转换成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)); }}