自定义View实战二:计步器的实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Androidtalent/article/details/80469485

一、概述


本文详细结合自定义 View 和 属性动画,讲述如何自定义一个圆弧计步器。

二、实现步骤分析


  1. 确定自定义属性,编写attrs.xml
  2. 在自定义View中获取自定义属性,做好初始化工作
  3. onMeasure(int widthMeasureSpec, int heightMeasureSpec) 确保正方形
  4. onDraw(Canvas canvas) 画外圆弧、内圆弧、文字
  5. 提供调用方法

三、具体实现


  1. 确定自定义属性,编写attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="StepView">
        <attr name="outerColor" format="color" />
        <attr name="innerColor" format="color" />
        <attr name="borderWidth" format="dimension" />
        <attr name="stepTextSize" format="dimension" />
        <attr name="stepTextColor" format="color" />
    </declare-styleable>
</resources>
  1. 在自定义View中获取自定义属性,做好初始化工作
public StepView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.StepView);
        mOuterColor = array.getColor(R.styleable.StepView_outerColor,mOuterColor);
        mInnerColor = array.getColor(R.styleable.StepView_innerColor, mInnerColor);
        mBorderWidth = (int) array.getDimension(R.styleable.StepView_borderWidth,mBorderWidth);
        mStepTextSize = array.getDimensionPixelSize(R.styleable.StepView_stepTextSize,mStepTextSize);
        mStepTextColor = array.getColor(R.styleable.StepView_stepTextColor, mStepTextColor);
        array.recycle();

        mOutPaint = new Paint();
        mOutPaint.setAntiAlias(true);
        mOutPaint.setStrokeWidth(mBorderWidth);
        mOutPaint.setColor(mOuterColor);
        mOutPaint.setStrokeCap(Paint.Cap.ROUND);
        mOutPaint.setStyle(Paint.Style.STROKE);      // 画笔空心

        mInnerPaint = new Paint();
        mInnerPaint.setAntiAlias(true);
        mInnerPaint.setStrokeWidth(mBorderWidth);
        mInnerPaint.setColor(mInnerColor);
        mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
        mInnerPaint.setStyle(Paint.Style.STROKE);    // 画笔空心


        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setColor(mStepTextColor);
        mTextPaint.setTextSize(mStepTextSize);
        // 宽高默认 30 dp
        width = dp2px(context, 30);
        height = dp2px(context, 30);
    }
  1. onMeasure(int widthMeasureSpec, int heightMeasureSpec) 确保正方形
@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 调用者在布局文件中可能  wrap_content
        // 获取模式 AT_MOST  默认30 dp

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode != MeasureSpec.AT_MOST){
            width = MeasureSpec.getSize(widthMeasureSpec);
        }
        if (heightMode != MeasureSpec.AT_MOST){
            height = MeasureSpec.getSize(heightMeasureSpec);
        }
        // 宽度高度不一致 取最小值,确保是个正方形
        setMeasuredDimension(width > height ? height : width, width > height ? height : width);
    }
  1. onDraw(Canvas canvas) 画外圆弧、内圆弧、文字
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // int center = getWidth() / 2;
        // int radius = getWidth() / 2 - mBorderWidth / 2;
        // RectF rectF = new RectF(center - radius,center - radius ,center + radius,center + radius);
        // 下面代码由上面代码简化而成
        RectF rectF = new RectF(mBorderWidth / 2 + getPaddingLeft(),mBorderWidth / 2 + getPaddingTop()
        ,getWidth() - (mBorderWidth / 2 + getPaddingRight()),getHeight() - (mBorderWidth / 2 + getPaddingBottom()));

        canvas.drawArc(rectF,135,270,false,mOutPaint);

        if(mStepMax == 0) return;
        // 画内圆弧  怎么画肯定不能写死  百分比  是使用者设置的从外面传
        float sweepAngle = (float)mCurrentStep / mStepMax;
        canvas.drawArc(rectF, 135, sweepAngle * 270, false, mInnerPaint);

        //  画文字
        String stepText = mCurrentStep+"";
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
        int dx = getWidth() / 2 - textBounds.width() / 2;
        // 基线 baseLine
        Paint.FontMetricsInt  fontMetrics = mTextPaint.getFontMetricsInt();
        int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        int baseLine = getHeight() / 2 + dy;
        canvas.drawText(stepText,dx,baseLine,mTextPaint);
    }
  1. 提供调用方法
/**
     * 设置步数最大值
     * @param stepMax
     */
    public synchronized void setStepMax(int stepMax){
        this.mStepMax = stepMax;
    }

    /**
     * 设置当前步数
     * @param currentStep
     */
    public synchronized void setCurrentStep(int currentStep){
        this.mCurrentStep = currentStep;
        // 刷新
        invalidate();
    }

四、结合属性动画使用


xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.vegen.StepView
        android:id="@+id/step_view"
        app:outerColor="@color/colorPrimary"
        app:innerColor="@color/colorAccent"
        app:borderWidth="20dp"
        app:stepTextColor="@color/colorAccent"
        app:stepTextSize="30sp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

Activity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final StepView qqStepView = (StepView) findViewById(R.id.step_view);
        qqStepView.setStepMax(10000);

        // 属性动画
        ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 8000);
        valueAnimator.setDuration(1000);
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float currentStep = (float) animation.getAnimatedValue();
                qqStepView.setCurrentStep((int)currentStep);
            }
        });
        valueAnimator.start();
    }
}

五、最终实现的效果

效果图

猜你喜欢

转载自blog.csdn.net/Androidtalent/article/details/80469485
今日推荐