Android自定义刻度尺的实现思路以及步骤

Posted 隔壁小王66

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义刻度尺的实现思路以及步骤相关的知识,希望对你有一定的参考价值。

最近一直在学自定义view,博大精深,感觉如果向底层看的话,功力不够且时间不允许,所以一直都是停留在怎么实现自定义view上,而为何会这么实现以及差异并没有考虑的很清晰,因为面向对象编程以及封装,都是让我们将功能抽出来使用,而不是去考虑每个功能里是怎么实现的,所以很苦恼,还是先实现吧,至于原理慢慢理解吧!

这是自定义View学习的第三篇,学习主要是在项目的基础上来学,并不是一点点的基础死扣,因为你看懂,敲出来一个自定义view的代码,你就会慢慢有所理解,包括中间的一些计算,所以还是建议大家先去敲代码,自己写不出来,就把别人的代码敲一遍,去理解一遍,比仅仅去看会领悟的更多,这就有点书读百遍,其义自现的意思,哈哈,一点浅见,谁让我笨呢。

今天讲一下自定义刻度尺的实现,咋听刻度尺,难度并不高,但是对于刚刚开始动手敲,摆脱Ctrl+c/Ctrl+z的同学来说还是有些难度的。

看看我的实现效果吧:

横向显示10cm,模拟器暂时找不到横屏,就这样吧!@_@

思路呢?

刚开始敲的时候,先明确思路,磨刀不误砍柴工,进去就敲最后敲得自己也糊涂了!

1:画刻度尺
2:画刻度数
3:画红线标记
4:处理滑动

画刻度尺

 canvas.save();
        for (int i = min; i < max; i++) 
            if (i % 10 == 0) 
                //起点x坐标10像素,画厘米线
                canvas.drawLine(10, 0, 10, 72, mLinePaint);
                String text = i / 10 + "";
                Rect rect = new Rect();
                float txtWidth = mTextPaint.measureText(text);
                mTextPaint.getTextBounds(text, 0, text.length(), rect);
                canvas.drawText(text, 10 - txtWidth / 2, 72 + rect.height() + 10, mTextPaint);
             else if (i % 5 == 0) 
                //每隔0.5cm画间隔线
                canvas.drawLine(10, 0, 10, 64, mLinePaint);
             else 
                //画毫米线
                canvas.drawLine(10, 0, 10, 48, mLinePaint);
            
            //每隔18像素移动一次,达到画线效果
            canvas.translate(18, 0);
        
        canvas.restore();

画刻度数

if (i % 10 == 0) 
                //起点x坐标10像素,画厘米线
                canvas.drawLine(10, 0, 10, 72, mLinePaint);
                //计算刻度数
                String text = i / 10 + "";
                Rect rect = new Rect();
                //获取文本宽度
                float txtWidth = mTextPaint.measureText(text);
                mTextPaint.getTextBounds(text, 0, text.length(), rect);
                //画字
                canvas.drawText(text, 10 - txtWidth / 2, 72 + rect.height() + 10, mTextPaint);
            

画红线标记

看效果图:

很明显,是一条线,外加一个圆。计算好距离就ok。

//画线
 canvas.drawLine(progrees, 0, progrees, 160, mRulerPaint);
 //线下画圆
        canvas.drawCircle(progrees, 170, 10, mRulerPaint);
        BigDecimal bd = new BigDecimal((progrees - 18) / 180);
        bd = bd.setScale(1, BigDecimal.ROUND_HALF_UP);
        //计算刻度数,保留一位小数,单位cm
        mTextPaint.setTextSize(48);
        canvas.drawText(bd.floatValue() + "cm", 500, 400, mTextPaint);

progrees是手指触摸的x轴坐标,线高160,圆心y轴坐标170,半径10即可。

处理滑动

 @Override
    public boolean onTouchEvent(MotionEvent event) 
        switch (event.getAction()) 
            case MotionEvent.ACTION_DOWN:
                isCanMove = true;
                break;
            case MotionEvent.ACTION_MOVE:
                if (!isCanMove) 
                    return false;
                
                //前面0坐标线从10像素开始,故而计算的时候要-10
                float x = event.getX() - 10;
                progrees = x;
                //刷新
                invalidate();
                break;
        
        return true;
    

绘画步骤就是这么多。

完整代码:

package com.example.com.testview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.math.BigDecimal;

/**
 * 刻度尺
 * Created by Administrator on 2016/9/14.
 */
public class ScaleView extends View 

    private Paint mLinePaint;
    private Paint mTextPaint;
    private Paint mRulerPaint;
    private float progrees = 10;
    private int max = 101;
    private int min = 0;
    private boolean isCanMove;

    public ScaleView(Context context) 
        super(context);
        init();
    

    public ScaleView(Context context, AttributeSet attrs) 
        super(context, attrs);
        init();
    

    public ScaleView(Context context, AttributeSet attrs, int defStyleAttr) 
        super(context, attrs, defStyleAttr);
        init();
    

    private void init() 
        mLinePaint = new Paint();
        mLinePaint.setColor(Color.CYAN);
        mLinePaint.setAntiAlias(true);//抗锯齿
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setStrokeWidth(4);
        mTextPaint = new Paint();
        mTextPaint.setColor(Color.CYAN);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setStrokeWidth(2);
        mTextPaint.setTextSize(48);
        //
        mRulerPaint = new Paint();
        mRulerPaint.setAntiAlias(true);
        mRulerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mRulerPaint.setColor(Color.RED);
        mRulerPaint.setStrokeWidth(4);
    

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(setMeasureWidth(widthMeasureSpec), setMeasureHeight(heightMeasureSpec));
    

    private int setMeasureHeight(int spec) 
        int mode = MeasureSpec.getMode(spec);
        int size = MeasureSpec.getSize(spec);
        int result = Integer.MAX_VALUE;
        switch (mode) 
            case MeasureSpec.AT_MOST:
                size = Math.min(result, size);
                break;
            case MeasureSpec.EXACTLY:
                break;
            default:
                size = result;
                break;
        
        return size;
    

    private int setMeasureWidth(int spec) 
        int mode = MeasureSpec.getMode(spec);
        int size = MeasureSpec.getSize(spec);
        int result = Integer.MAX_VALUE;
        switch (mode) 
            case MeasureSpec.AT_MOST:
                size = Math.min(result, size);
                break;
            case MeasureSpec.EXACTLY:
                break;
            default:
                size = result;
                break;
        
        return size;
    

    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);
        canvas.save();
        for (int i = min; i < max; i++) 
            if (i % 10 == 0) 
                canvas.drawLine(10, 0, 10, 72, mLinePaint);
                String text = i / 10 + "";
                Rect rect = new Rect();
                float txtWidth = mTextPaint.measureText(text);
                mTextPaint.getTextBounds(text, 0, text.length(), rect);
                canvas.drawText(text, 10 - txtWidth / 2, 72 + rect.height() + 10, mTextPaint);
             else if (i % 5 == 0) 
                canvas.drawLine(10, 0, 10, 64, mLinePaint);
             else 
                canvas.drawLine(10, 0, 10, 48, mLinePaint);
            
            canvas.translate(18, 0);
        
        canvas.restore();
        canvas.drawLine(progrees, 0, progrees, 160, mRulerPaint);
        canvas.drawCircle(progrees, 170, 10, mRulerPaint);
        BigDecimal bd = new BigDecimal((progrees - 18) / 180);
        bd = bd.setScale(1, BigDecimal.ROUND_HALF_UP);
        mTextPaint.setTextSize(48);
        canvas.drawText(bd.floatValue() + "cm", 500, 400, mTextPaint);
    

    @Override
    public boolean onTouchEvent(MotionEvent event) 
        switch (event.getAction()) 
            case MotionEvent.ACTION_DOWN:
                isCanMove = true;
                break;
            case MotionEvent.ACTION_MOVE:
                if (!isCanMove) 
                    return false;
                
                float x = event.getX() - 10;
                progrees = x;
                invalidate();
                break;
        
        return true;
    

布局:

 <com.example.com.testview.ScaleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="4dp"/>

现在看一下横向效果:

代码就不上传了,上面就是。

以上是关于Android自定义刻度尺的实现思路以及步骤的主要内容,如果未能解决你的问题,请参考以下文章

Android自定义一个属于自己的时间钟表

Android自定义View之区块选择器

Android 自定义View:实现一个 FM 刻度尺

Android自定义一个属于自己的刻度尺

Android自定义尺子控件(选择身高体重等)

Android自定义尺子控件(选择身高体重等)