QQ运动的记步进度条实现
程序员文章站
2022-05-29 15:19:48
...
今天突然看到QQ计步器样式更新了,变的还挺快
我自己构思实现 和QQ还是有差别的但是基本样式实现了。
下来看代码 代码里面基本都全是注释。
package com.zyf.customview.view;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import com.zyf.customview.R;
/**
* 作者:小飞
* 创建于 2018年4月16日 17:46:36
*/
public class QQCustomView extends View {
/**
* 画笔
* */
private Paint mPaint;
/**
* 文字画笔
* */
private Paint mTextPaint;
/**
* 文字画笔
* */
private Paint mSmallTextPaint;
/**
* 填充进度颜色
* */
private int insideColor;
/**
* 背景颜色
* */
private int outsideColor;
/**
* 文字颜色
* */
private int textColor;
/**
* 宽
* */
private int width;
/**
* 高
* */
private int height;
/**
* 当前进度条
* */
private int currentProgress = 0;
/**
* 进度的百分比
* */
private int progress;
/**
* 文字的高度
* */
private int textheight;
/**
* 步数
* */
private int steps;
/**
* 最大步数
* */
private int stepsCount = 5000;
/**
* 单位
* */
private String company;
/**
* 弧线的宽度
* */
private int arcStrokeWidth = 20;
/**
* 弧线的间距
* */
private float spacingWidth = 2;
/**
* 进度监听
* */
private OnViewProgressListener listener;
public QQCustomView(Context context) {
this(context,null);
}
public QQCustomView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public QQCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ty = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView,0,0);
try {
insideColor = ty.getColor(R.styleable.CustomView_inside_color,0xFF40B3FF);
outsideColor = ty.getColor(R.styleable.CustomView_outside_color,0xFF737171);
textColor = ty.getColor(R.styleable.CustomView_text_color,0xFF40B3FF);
steps = ty.getInt(R.styleable.CustomView_step,0);
stepsCount = ty.getInt(R.styleable.CustomView_step_count,5000);
company = ty.getString(R.styleable.CustomView_company);
arcStrokeWidth = ty.getInt(R.styleable.CustomView_arc_stroke_width,20);
if(TextUtils.isEmpty(company)){
company = "步";
}
}finally {
ty.recycle();
}
init();
}
/**
* 初始化属性
* <attr name="inside_color" format="color"></attr>
* <attr name="outside_color" format="color"></attr>
* <attr name="text_color" format="color"></attr>
* */
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(5);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(100);
mTextPaint.setColor(textColor);
textheight = (int)(mTextPaint.ascent()+mTextPaint.descent());
mSmallTextPaint = new Paint();
mSmallTextPaint.setAntiAlias(true);
mSmallTextPaint.setTextSize(50);
mSmallTextPaint.setColor(textColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
width = measureSize(widthMeasureSpec);
height = measureSize(heightMeasureSpec);
setMeasuredDimension(width,height);
}
private int measureSize(int measureSpec) {
int length;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
if(mode == MeasureSpec.EXACTLY){
length = size;
}else{
length = 500;
if(mode == MeasureSpec.AT_MOST){
length = Math.min(length,size);
}
}
return length;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(listener!=null){
listener.onProgress(currentProgress);
}
drawInside(canvas);
drawOutside(canvas,currentProgress);
drawText(canvas,currentProgress);
}
/**
* 画字
* */
private void drawText(Canvas canvas,int steps) {
String str = steps+"";
int textWidth = (int)mTextPaint.measureText(str);
int textsWidth = (int)mSmallTextPaint.measureText(company);
int countWidth = textsWidth +textWidth;
canvas.drawText(str,0,str.length(),(width-countWidth)/2,(height-textheight)/2,mTextPaint);
canvas.drawText(company,0,1,(width+textWidth-textsWidth)/2,(height-textheight)/2,mSmallTextPaint);
}
/**
* 画背景
* */
private void drawInside(Canvas canvas) {
mPaint.setColor(outsideColor);
canvas.save();
//这里270的意思是旋转270的弧线的意思
//(float) (width/2 + width/2 * Math.cos(135f*Math.PI/180))
// 计算的是 135度的情况下 圆上的点位置 计算两个同一半径直线上的两个点画线 旋转画布角度 重复画 就达到了所有的刻度
for (float i = 0; i < 270/spacingWidth; i++) {
canvas.drawLine((float) (width/2 + width/2 * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2) * Math.sin(135f*Math.PI/180)),
(float) (width/2 + (width/2-arcStrokeWidth) * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2-arcStrokeWidth) * Math.sin(135f*Math.PI/180)), mPaint);
canvas.rotate(spacingWidth, getWidth() / 2, getHeight() / 2);
}
canvas.restore();
}
/**
* 画进度
* */
private void drawOutside(Canvas canvas,int progress) {
float angle;
if((progress/(stepsCount*1f))*270>270){
angle = 270;
}else {
angle = (progress/(stepsCount*1f))*270;
}
mPaint.setColor(insideColor);
mPaint.setStyle(Paint.Style.STROKE);
canvas.save();
for (float i = 0; i < angle/spacingWidth; i++) {
canvas.drawLine((float) (width/2 + width/2 * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2) * Math.sin(135f*Math.PI/180)),
(float) (width/2 + (width/2-arcStrokeWidth) * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2-arcStrokeWidth) * Math.sin(135f*Math.PI/180)), mPaint);
canvas.rotate(spacingWidth, getWidth() / 2, getHeight() / 2);
}
canvas.restore();
}
/**
* 设置当前进度
* */
public void setCurrentProgress(int currentProgress) {
this.currentProgress = currentProgress;
invalidate();
}
/**
* 属性动画
* */
ValueAnimator anim;
private void animatorMethod(){
if(anim!=null&&anim.isRunning()){
return;
}
anim = ValueAnimator.ofInt(0,steps);
anim.setDuration(3000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentProgress = (int)animation.getAnimatedValue();
invalidate();
}
});
anim.start();
}
public void setSteps(int steps) {
this.steps = steps;
animatorMethod();
}
/**
* 设置线条宽度
* */
public void setArcStrokeWidth(int arcStrokeWidth) {
if(arcStrokeWidth<10){
return;
}
this.arcStrokeWidth = arcStrokeWidth;
invalidate();
}
/**
* 设置线条间距
* */
public void setSpacingWidth(float spacingWidth) {
if(spacingWidth<1){
return;
}
this.spacingWidth = spacingWidth;
invalidate();
}
public interface OnViewProgressListener{
void onProgress(int progress);
}
/**
* 设置监听
* */
public void setListener(OnViewProgressListener listener) {
this.listener = listener;
}
}
里面的自定义属性不用关注 上面有属性注释 自己也可以直接初始化即可
上一篇: 实现记步样式的进度条