美文网首页
自定义View实战二:计步器的实现

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

作者: 老师好我是小明同学 | 来源:发表于2018-05-27 15:05 被阅读19次

    一、概述


    本文详细结合自定义 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();
        }
    }
    

    五、最终实现的效果

    xiaoguotu.jpg

    相关文章

      网友评论

          本文标题:自定义View实战二:计步器的实现

          本文链接:https://www.haomeiwen.com/subject/uzxvjftx.html