就是一个很简单的自定义View
进入应用圆弧动画过度增加到指定位置并显示步数
话不多说我们开搞
attrs.xml
- 获取自定义属性值
- 测量布局视图大小
- 绘制圆弧文字
- 设置动画
- 简单基础封装一下
上代码中有详细注释:
MyStepView.java 自定义View
public class MyStepView extends View {
private int mOuterColor;//外圆弧颜色
private int mInnerColor;//内圆弧颜色
private int mBorderWidth;//圆弧宽度
private int mStepTextColor;//显示当前步数颜色
private int mCurrentStep;//当前步数
private int mStepTextSize;//显示当前步数文本
private Paint mOuterPaint;//外圆弧画笔
private Paint mInnerPaint;//内圆弧画笔
private int mMaxStep;//目标步数
private Paint mTextPaint;//文本画笔
private Paint mTextPaintX;//提示信息画笔
private int offset = 0;//动画偏移量
public MyStepView(Context context) {
super(context);
}
public MyStepView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyStepView);//获取自定义属性值
mOuterColor = array.getColor(R.styleable.MyStepView_outerarc_color, mOuterColor);
mInnerColor = array.getColor(R.styleable.MyStepView_innerarc_color, mInnerColor);
mBorderWidth = (int) array.getDimension(R.styleable.MyStepView_boorder_width, 0);
mStepTextColor = array.getColor(R.styleable.MyStepView_steptext_color, mStepTextColor);
mStepTextSize = array.getDimensionPixelSize(R.styleable.MyStepView_steptext_size, mStepTextSize);
array.recycle();//回收
mOuterPaint = new Paint();
mOuterPaint.setAntiAlias(true);
mOuterPaint.setColor(mOuterColor);
mOuterPaint.setStrokeWidth(mBorderWidth);
mOuterPaint.setStyle(Paint.Style.STROKE);
mOuterPaint.setStrokeCap(Paint.Cap.ROUND);
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setColor(mInnerColor);
mInnerPaint.setStrokeWidth(mBorderWidth);
mInnerPaint.setStyle(Paint.Style.STROKE);
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(mStepTextColor);
mTextPaint.setTextSize(mStepTextSize);
mInnerPaint.setFakeBoldText(true);
mTextPaintX = new Paint();
mTextPaintX.setAntiAlias(true);
mTextPaintX.setColor(mStepTextColor);
mTextPaintX.setTextSize(70);
mTextPaintX.setFakeBoldText(true);
}
public MyStepView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/*测量*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
}
/*绘制*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int center = getWidth() / 2;
int radius = (getWidth() - mBorderWidth) / 2;
RectF rectF = new RectF(mBorderWidth / 2, mBorderWidth / 2, center + radius, center + radius);
canvas.drawArc(rectF, 135, 270, false, mOuterPaint);//绘制内圆弧
if (mMaxStep == 0) {//如果目标值为0 可以不绘制
return;
}
float radio = (float) offset / mMaxStep;
canvas.drawArc(rectF, 135, 270 * radio, false, mInnerPaint);//绘制外圆弧
String mText = offset + "";
Rect rect = new Rect();
mTextPaint.getTextBounds(mText, 0, mText.length(), rect);//获取文本框
int dx = getWidth() / 2 - rect.width() / 2;
canvas.drawText(mText, dx, getWidth() / 2 + rect.height() / 2, mTextPaint);//绘制文字
if (offset == mCurrentStep) {//执行完动画 显示当前步数和目标值
String mTextMax = "今日目标:" + mMaxStep;
String mTextCurrent = "已完成:" + mCurrentStep;
Rect rectMaxstep = new Rect();
Rect rectCurrentStep = new Rect();
mTextPaintX.getTextBounds(mTextMax, 0, mTextMax.length(), rectMaxstep);//获取文本框
mTextPaintX.getTextBounds(mTextCurrent, 0, mTextCurrent.length(), rectCurrentStep);//获取文本框
canvas.drawText(mTextMax, dx - 50, getWidth() + rectMaxstep.height() + 200, mTextPaintX);//绘制文字 今日目标
canvas.drawText(mTextCurrent, dx - 50, getWidth() + rectCurrentStep.height() + 300, mTextPaintX);//绘制文字 已完成
}
}
/*开始动画*/
public void startUi() {
ValueAnimator animator = ObjectAnimator.ofFloat(0, mCurrentStep);//属性动画插值器
animator.addUpdateListener((animation -> {//lambda表达式
float animatedValue = (float) animation.getAnimatedValue();
offset = (int) animatedValue;//实现变化过程
postInvalidate();//重绘刷新整个View
}));
animator.setDuration(3000);//设置动画持续时间
animator.start();//开始执行动画
}
/*设置目标最大值*/
public void setmMaxStep(int mMaxStep) {
this.mMaxStep = mMaxStep;
}
/*设置当前步数*/
public void setmCurrentStep(int mCurrentStep) {
this.mCurrentStep = mCurrentStep;
}
}
activity_main.xml
MainActivity.java
public class MainActivity extends AppCompatActivity {
private MyStepView myStepView;
@Override
protected void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);/*不显示标题*/
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);/*全屏设置*/
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//强制竖屏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//版本判断
// Translucent status bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//设置statusbar应用所占的屏幕扩大到全屏,但是最顶上会有背景透明的状态栏,它的文字可能会盖着你的应用的标题栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myStepView = findViewById(R.id.myStepView);//绑定
myStepView.setmMaxStep(1500);//设置最大目标
myStepView.setmCurrentStep(1314);//设置当前步数
myStepView.startUi();//开始动画
}
}
简单完成啦!
项目链接