自定义控件:5分钟手写计步器

作者: 毛先森 | 来源:发表于2018-12-06 18:10 被阅读9次

    前言

    自定义控件是每个 Android 应用开发者的必备技能,所以一起来试着手写自定义控件,挑战自定义 View 中最好玩的 onDraw.

    我们仿照 QQ 计步器的样式来做,主要熟悉画笔(Paint)的使用技巧

    控件效果

    在这里感谢红橙Darren老师的指导

    绘制步骤

    • 自定义属性
    • 继承 View
    • 绘制背景圆弧
    • 绘制前景圆弧
    • 绘制文字
    • 设置方法

    自定义属性

       // 自定义计步器控件属性
        <declare-styleable name="CustomFilterView">
            // 背景圆弧颜色
            <attr name="backgroundViewColor" format="color"/>
            // 前景圆弧颜色
            <attr name="fontViewColor" format="color"/>
            // 圆弧宽度
            <attr name="stepViewArcWidth" format="dimension"/>
            // 字体颜色
            <attr name="stepViewTextColor" format="color"/>
            // 字体大小
            <attr name="stepViewTextSize" format="dimension"/>
            // 最大步数
            <attr name="maxStepCount" format="integer"/>
            // 当前步数
            <attr name="currentStepCount" format="integer"/>
        </declare-styleable>
    

    继承 View

    重写三个构造方法,读取自定义属性,重写onDraw

       public FootStepCounterView(Context context) {
            this(context,null);
        }
    
        public FootStepCounterView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
    
        }
    
        public FootStepCounterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomFilterView);
            bgViewColor = typedArray.getColor(R.styleable.CustomFilterView_backgroundViewColor, Color.RED);
            fontViewColor = typedArray.getColor(R.styleable.CustomFilterView_fontViewColor,Color.YELLOW);
            stepViewColor = typedArray.getColor(R.styleable.CustomFilterView_stepViewTextColor,Color.YELLOW);
            stepViewTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomFilterView_stepViewTextSize,100);
            stepViewTextColor = typedArray.getColor(R.styleable.CustomFilterView_stepViewTextColor, Color.YELLOW);
            stepViewArcWidth = typedArray.getDimensionPixelOffset(R.styleable.CustomFilterView_stepViewArcWidth,10);
            maxStep = typedArray.getInt(R.styleable.CustomFilterView_maxStepCount,DEFAULT_MAX_STEP);
            mCurrentFootstep = typedArray.getInt(R.styleable.CustomFilterView_currentStepCount, DEFAULT_MAX_STEP);
            typedArray.recycle();
            init();
        }
    
        private void init() {
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            stringBuffer = new StringBuffer();
        }
    

    绘制背景圆弧

     private void drawBgArc(Canvas canvas) {
            // 设置画笔: 宽度
            mPaint.setStrokeWidth(stepViewArcWidth);
            // 始末端圆角
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            // 拐角处圆角
         //   mPaint.setStrokeJoin(Paint.Join.ROUND);
            // 实线
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(bgViewColor);
            // 设置可操作区域
         //   RectF rectF = new RectF(left,top,right,bottom);
            canvas.drawArc(rectF,135,270,false,mPaint);
        }
    
    • 重写onDraw
      @Override
        protected void onDraw(Canvas canvas){
            // 绘制背景圆弧
            drawBgArc(canvas);
            // 绘制上层圆弧
            drawFontArc(canvas);
            // 绘制文字
            drawText(canvas);
        }
    
    

    绘制前景圆弧

     private void drawFontArc(Canvas canvas) {
            mPaint.setColor(fontViewColor);
            float percentage = (float) ((double)getCurrentFootstep()/(double) maxStep)*100;
            canvas.drawArc(rectF,135,(percentage*270)/100,false,mPaint);
        }
    

    绘制文字

    绘制文字时需要注意基线的位置,在这个控件中基线位于整个控件空心点偏下的位置.

    private void drawText(Canvas canvas) {
            // 重置画笔
            mPaint.reset();
            mPaint.setAntiAlias(true);
            mPaint.setTextSize(stepViewTextSize);
            mPaint.setColor(stepViewColor);
            // 设置基线
    
            stringBuffer.append(getCurrentFootstep());
            stringBuffer.append("步");
            Rect rect = new Rect();
            mPaint.getTextBounds(stringBuffer.toString(),0, stringBuffer.toString().length(),rect);
            Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
            int baselineX = ( stepViewWidth - rect.width())/2;
            int baselineY = (stepViewHeight / 2) + (int) (fontMetrics.bottom-fontMetrics.top)/4;
            canvas.drawText(stringBuffer.toString(),baselineX,baselineY,mPaint);
            stringBuffer.setLength(0);
        }
    

    设置方法

    计步器需要提供一个设置步数的方法,并在调用此方法时重绘控件来刷新数据

     // 获取当前步数
        public synchronized int getCurrentFootstep() {
            return mCurrentFootstep;
        }
        // 设置当前步数
        public synchronized void setCurrentFootstep(int mCurrentFootstep) {
            this.mCurrentFootstep = mCurrentFootstep;
            invalidate();
        }
    
    

    相关文章

      网友评论

        本文标题:自定义控件:5分钟手写计步器

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