实现一个简单的计步器功能

2021-07-09  本文已影响0人  乌托邦式的爱情

废话不多说,直接上效果图


1.自定义步数效果图.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();
    }
}

上一篇 下一篇

猜你喜欢

热点阅读