废话不多说,直接上效果图
![](https://img.haomeiwen.com/i4770284/2716e3c5d90411ac.gif)
相信这个效果大家都不会陌生,作为自定义View的开篇章节,我们先牛刀小试一把。一般情况下,当我们拿到美工或者产品需要我们实现的效果图时,不要急于去写代码,而是应该好好去分析一下到底该如何去实现这个功能,就这个功能而言,我给它拆分为几个部分:
1.底部的总步数条(固定)
2.加载的步数条(变动)
3.对应显示的文字步数
接下来我们就一步一步来看到底怎么做:
(1)首先我们的底部的总步数条颜色不能写死,加载的步数条颜色也不能写死还有步数条宽度的大小也不能写死,除此之外显示的文字步数(字体大小、颜色)也不能写死,所以,我们需要通过自定义属性的方式让用户自己设定。
<!-- 计步器的自定义样式 -->
<declare-styleable name="StepView">
<attr name="step_view_fix_progress_color" format="color"/>
<attr name="step_view_current_progress_color" format="color"/>
<attr name="step_view_progress_size" format="dimension"/>
<attr name="step_view_text_color" format="color"/>
<attr name="step_view_text_size" format="dimension"/>
</declare-styleable>
(2)获取自定义样式之后就需要给我们的每个部分设置画笔了
// 画文字的画笔
private Paint mTextPaint;
// 设置最大的步数
private int mMaxStep;
// 设置当前的步数
private int mCurrentStep;
public StepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 省略代码
// 设置画笔
mFixProgressPaint = initPaint(mFixedProgressColor);
mCurrentProgressPaint = initPaint(mCurrentProgressColor);
mTextPaint = new Paint();
// 抗锯齿
mTextPaint.setAntiAlias(true);
// 防抖动
mTextPaint.setDither(true);
// 设置画笔的颜色
mTextPaint.setColor(mTextColor);
// 设置画笔的大小
mTextPaint.setTextSize(mTextSize);
}
private Paint initPaint(int color) {
Paint paint = new Paint();
// 抗锯齿
paint.setAntiAlias(true);
// 防抖动
paint.setDither(true);
// 设置画笔的颜色
paint.setColor(color);
// 设置画笔的大小
paint.setStrokeWidth(mProgressSize);
// 设置画笔的样式
paint.setStyle(Paint.Style.STROKE);
// 设置画笔的端的样式
paint.setStrokeCap(Paint.Cap.ROUND);
return paint;
}
(3)在我们的onDraw()方法里面去画了
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 1.画固定的圆弧
RectF rectF = new RectF(mProgressSize / 2, mProgressSize / 2, getWidth() - mProgressSize / 2, getHeight() - mProgressSize / 2);
canvas.drawArc(rectF, 135, 270, false, mFixProgressPaint);
// 2.画非固定圆弧
if (mCurrentStep < 1) {
return;
}
canvas.drawArc(rectF, 135, (float) mCurrentStep / mMaxStep * 270, false, mCurrentProgressPaint);
// 3.画文字
String value = String.valueOf(mCurrentStep);
// 3.1计算文字的宽度和高度
Rect rect = new Rect();
mTextPaint.getTextBounds(value, 0, value.length(), rect);
float x = getWidth() / 2 - rect.width() / 2;
// 计算基线
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
float y = getHeight() / 2 + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
canvas.drawText(value, x, y, mTextPaint);
}
(4)配合我们的属性动画实现动态效果
private fun startStep(){
step_view.setMaxStep(4000)
val valueAnimation = ObjectAnimator.ofInt(0,3000)
valueAnimation.duration = 1000
valueAnimation.addUpdateListener {
val value:Int = it.animatedValue as Int
step_view.setCurrentStep(value)
}
valueAnimation.start()
}
最后贴上完整代码如下:
public class StepView extends View {
// 总步数对应的颜色
private int mFixedProgressColor = Color.GRAY;
// 当前步数对应的颜色
private int mCurrentProgressColor = Color.YELLOW;
// 进度条对应的大小
private int mProgressSize = 5;
// 字体对应的颜色
private int mTextColor = Color.YELLOW;
// 字体对应的大小(像素)
private int mTextSize = 15;
// 画总步数的画笔
private Paint mFixProgressPaint;
// 画变动步数的画笔
private Paint mCurrentProgressPaint;
// 画文字的画笔
private Paint mTextPaint;
// 设置最大的步数
private int mMaxStep;
// 设置当前的步数
private int mCurrentStep;
public StepView(Context context) {
this(context, null);
}
public StepView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public StepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 先理清一下思路,再来进行编码
// 整个功能分为3个部分,底部的总步数条(固定)、加载的步数条(变动)、对应显示的文字步数
// 1.获取自定义属性
// <1> 底部的总步数条颜色
// <2> 加载的步数条颜色
// <3> 步数条宽度
// <4> 显示的文字步数(字体大小、颜色)
// 2.通过draw()方法绘制静态效果
// 3.通过属性动画来实现动态加载
// 1.获取自定义属性
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.StepView);
mFixedProgressColor = array.getColor(R.styleable.StepView_step_view_fix_progress_color, mFixedProgressColor);
mCurrentProgressColor = array.getColor(R.styleable.StepView_step_view_current_progress_color, mCurrentProgressColor);
mProgressSize = array.getDimensionPixelSize(R.styleable.StepView_step_view_progress_size, mProgressSize);
mTextColor = array.getColor(R.styleable.StepView_step_view_text_color, mTextColor);
mTextSize = array.getDimensionPixelSize(R.styleable.StepView_step_view_text_size, mTextSize);
array.recycle();
// 设置画笔
mFixProgressPaint = initPaint(mFixedProgressColor);
mCurrentProgressPaint = initPaint(mCurrentProgressColor);
mTextPaint = new Paint();
// 抗锯齿
mTextPaint.setAntiAlias(true);
// 防抖动
mTextPaint.setDither(true);
// 设置画笔的颜色
mTextPaint.setColor(mTextColor);
// 设置画笔的大小
mTextPaint.setTextSize(mTextSize);
}
private Paint initPaint(int color) {
Paint paint = new Paint();
// 抗锯齿
paint.setAntiAlias(true);
// 防抖动
paint.setDither(true);
// 设置画笔的颜色
paint.setColor(color);
// 设置画笔的大小
paint.setStrokeWidth(mProgressSize);
// 设置画笔的样式
paint.setStyle(Paint.Style.STROKE);
// 设置画笔的端的样式
paint.setStrokeCap(Paint.Cap.ROUND);
return paint;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 1.画固定的圆弧
RectF rectF = new RectF(mProgressSize / 2, mProgressSize / 2, getWidth() - mProgressSize / 2, getHeight() - mProgressSize / 2);
canvas.drawArc(rectF, 135, 270, false, mFixProgressPaint);
// 2.画非固定圆
if (mCurrentStep < 1) {
return;
}
canvas.drawArc(rectF, 135, (float) mCurrentStep / mMaxStep * 270, false, mCurrentProgressPaint);
// 3.画文字
String value = String.valueOf(mCurrentStep);
// 3.1计算文字的宽度和高度
Rect rect = new Rect();
mTextPaint.getTextBounds(value, 0, value.length(), rect);
float x = getWidth() / 2 - rect.width() / 2;
// 计算基线
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
float y = getHeight() / 2 + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
canvas.drawText(value, x, y, mTextPaint);
}
/**
* 设置最大步数值
*
* @param maxStep 最大步数值
*/
public void setMaxStep(int maxStep) {
this.mMaxStep = maxStep;
}
/**
* 设置当前步数值
*
* @param currentStep 当前步数值
*/
public void setCurrentStep(int currentStep) {
this.mCurrentStep = currentStep;
invalidate();
}
}
网友评论