美文网首页
Android自定义view-QQ计步器效果

Android自定义view-QQ计步器效果

作者: 临窗听雨 | 来源:发表于2017-05-28 11:07 被阅读258次

    一、概述

       今天要讲的效果是类似qq计步器的效果,先看下效果图:
    
    qq计步器效果.gif

    二、思路分析

    看图说话,图中有两个圆弧,一个背景圆弧,一个能动态变化的圆弧,中间有记录步数的文字。三个对象,每个对象有各自的属性。然后就是设置各自对象的大小和各自对象的绘制了。

    2.1自定义属性

    attrs文件中的代码:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="QQStepView">
            <!--画笔颜色-->
            <attr name="outColor" format="color"></attr>
            <attr name="innerColor" format="color"></attr>
            <!--画笔的宽度大小-->
            <attr name="boderWidth" format="dimension"></attr>
            <!--文字的颜色和大小-->
            <attr name="stepColor" format="color"></attr>
            <attr name="stepSeize" format="dimension"></attr>
        </declare-styleable>
    </resources>
    

    定义了背景圆弧画笔和前景圆弧画笔的颜色及宽度,还有中间文字的颜色和尺寸打小,在构造函数中初始化。

    2.2构造函数代码

        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.QQStepView);
            mOutColor = a.getColor(R.styleable.QQStepView_outColor,mOutColor);
            mInnerColor = a.getColor(R.styleable.QQStepView_innerColor,mInnerColor);
            mStepTextSize = a.getDimensionPixelSize(R.styleable.QQStepView_stepSeize,sp2px(mStepTextSize));
            mBorderWidth = (int)a.getDimension(R.styleable.QQStepView_boderWidth,mBorderWidth);
            mStepTextColor = a.getColor(R.styleable.QQStepView_stepColor,mStepTextColor);
            a.recycle();
            mOutPaint = new Paint();
            mOutPaint.setAntiAlias(true); //抗锯齿
            mOutPaint.setColor(mOutColor);
            mOutPaint.setStrokeWidth(mBorderWidth);
            mOutPaint.setStyle(Paint.Style.STROKE);
            mInnerPaint = new Paint();
            mInnerPaint.setAntiAlias(true); //抗锯齿
            mInnerPaint.setColor(mInnerColor);
            mInnerPaint.setStrokeWidth(mBorderWidth);
            mInnerPaint.setStyle(Paint.Style.STROKE);
            mTextPaint = new Paint();
            mTextPaint.setColor(mStepTextColor);
            mTextPaint.setTextSize(mStepTextSize);
    

    构造函数没啥好讲的,都是套路

    2.3onMeasure方法设置控件宽高

     //onMeasure()
        @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);
        }
    

    2.4onDraw方法中对几个对象进行绘制

    @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //画外圆弧 ,内圆弧 ,文字
            int center = getWidth()/2;
            int radius = center - mBorderWidth/2; //外切圆压住描边的中间
            //指定圆弧的外轮廓矩形区域。比较易懂
            RectF rectF = new RectF(center - radius, center - radius, center
                    + radius, center + radius);
            canvas.drawArc(rectF,135,270,false,mOutPaint);
            if (mStepMax==0){
                return;
            }
            //这里要强制转换为float型的
            float sweepAngle = (float) mCurStep/mStepMax;
            canvas.drawArc(rectF,135,sweepAngle*270,false,mInnerPaint);
            String stepText = mCurStep+"";
            //画文字
            Rect bunds = new Rect();
            mTextPaint.getTextBounds(stepText,0,stepText.length(),bunds);
            int dy = (mTextPaint.getFontMetricsInt().bottom - mTextPaint.getFontMetricsInt().top)/2+mTextPaint.getFontMetricsInt().bottom;
            int baseLine = getHeight()/2+dy;
            canvas.drawText(stepText,getWidth()/2-bunds.width()/2,baseLine,mTextPaint);
        }
    

    这里对rectF的赋值不太懂的,可以参考这个链接:
    关于canvas.drawArc,canvas.drawOval 和RectF 的关系

    2.5其他方法

        // 写几个方法动起来
        public synchronized void setStepMax(int stepMax){
            this.mStepMax = stepMax;
        }
        public synchronized void setCurrentStep(int currentStep){
            this.mCurStep = currentStep;
            // 不断绘制  onDraw()
            invalidate();
        }
    

    解释一下,一个是设置你最大运动的步数,一个是设置你当前绘制到的那个步数,在此方法中调用invalidate方法,会不断调用onDraw方法进行绘制,这两个方法暴露给外部调用动态改变。

    2.6MainActivity的实现

      @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            final QQStepView qqStepView = (QQStepView) findViewById(R.id.step_view);
            qqStepView.setStepMax(4000);
            // 属性动画
            ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 3000);
            valueAnimator.setDuration(1000);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float currentStep = (float) animation.getAnimatedValue();
                    qqStepView.setCurrentStep((int)currentStep);
                }
            });
            valueAnimator.start();
        }
    

    用属性动画实现动画效果

    三、结语

    分析完毕,最后感谢,darren大神,具有无私分享精神,带着一起写效果,看源码。
    附上代码地址:http://pan.baidu.com/s/1qXGO4w8

    相关文章

      网友评论

          本文标题:Android自定义view-QQ计步器效果

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