Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

自定义View——模拟水银柱

$
0
0

由于项目需要,所以用SurfaceView写了一个自定义View,根据晓风飞雨的温度计源码做了一部分修改而来,效果是双汞柱 不废话了 先上源码

package view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.example.sc.bloodpressuremeter.R;

import java.text.DecimalFormat;

/**
 * TODO: document your custom view class.
 */
public class Thermometer extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private SurfaceHolder mHolder;
    private Canvas mCanvas;

    //定义左侧范围
    int left_temperatureRange = 15;
    //定义右侧范围
    int right_temperatureRange = 20;
    //定义一个盘快的范围
    private RectF mRange = new RectF();
    //定义温度计的宽度和中心宽度
    int mWith;
    int mHeight;
    int centerWith;
    int centerHeight;

    //定义温度计刻度总长度
    int temperatureAllLong;

    //定义一下水银的宽度
    int MercuryWith;
    //十的倍数的线长度
    int MaxLineLong;
    //五的倍数的线的长度
    int MidLineLong;
    //其他刻度线的长度
    int MinLineLong;
    //左侧刻度间隔
    float left_scaleLong;
    //右侧刻度间隔
    float right_scaleLong;

    //定义温度计距离画布的上宽度
    float abHeight;

    //绘制线条的画笔
    private Paint LinePaint;
    //绘制文本的画笔
    private Paint TextPaint1;
    //绘制单位的画笔
    private Paint TextPaint;


    //设置温度上升的速度
    private volatile float mSpeed = 0;
    //kpa上升的速度
    private volatile float mSpeed_kpa = 0;

    //设置背景图
    private Bitmap mBitmap;

    /**
     * 定义初始温度,当前显示正在变化也就是显示的温度,还有目标温度
     * 其中,初始温度不变,
     * 当前温度是有程序根据不同的速度和目标温度计算出来的,
     * 目标温度则是由仪器传送过来的数据
     */
    private float BeginTenperature = (float) 0;
    private int left_EndTenperature = 300;
    private int right_EndTenperature = 40;
    private volatile float CurrentTemperature = (float) 0;
    private volatile float CurrentLow_hight = (float) 0;

    float TargetTemperature = 0;
    float Targetlow_hight = 0;

    /**
     * 定义每一秒绘制的次数
     */
    int everySecondTime = 100;

    //设置文字的大小
    private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT, 25, getResources().getDisplayMetrics());
    private float mTextSize_ten = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT, 10, getResources().getDisplayMetrics());
    private float mSymbolTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT, 35, getResources().getDisplayMetrics());
    private float mShowSymbolTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT, 45, getResources().getDisplayMetrics());
    /**
     * 用户绘制的线程
     */
    private Thread mThread;
    /**
     * 根据目标温度改变要显示的当前温度的线程
     */
    private Thread mChangeTemperatureThread;

    /**
     * 设置一个标志位,用于线程的开启还是关闭的标志
     *
     * @param context
     */
    private Boolean isRunning, isRunning_kpa;

    private DecimalFormat fomat;//格式化float

    public Thermometer(Context context) {
        this(context, null);
    }

    public Thermometer(Context context, AttributeSet attrs) {
        super(context, attrs);
        mHolder = getHolder();
        mHolder.addCallback(this);

    }

    @Override
    protected void onMeasure(int with, int height) {
        super.onMeasure(with, height);
        this.mWith = getMeasuredWidth() / 2;
        this.mHeight = getMeasuredHeight();
        //这里先把中心设置在屏幕的中心
        this.centerWith = mWith / 2 + 100;
        this.centerHeight = mHeight / 2;
        //设置水银的宽度
        MercuryWith = mWith / 6;
        MinLineLong = MercuryWith;
        MidLineLong = MinLineLong * 8 / 6;
        MaxLineLong = MidLineLong * 3 / 2;
        //temperatureAllLong表示温度刻度总长度
        temperatureAllLong = mHeight * 9 / 10;
        //设置左侧刻度间隔,包含了刻度线的长度
        left_scaleLong = temperatureAllLong / left_temperatureRange / 10.0f;//表示一个温度十个刻度

        //设置右侧刻度间隔,包含了刻度线的长度
        right_scaleLong = temperatureAllLong / right_temperatureRange / 5.0f;//表示一个温度5个刻度

        abHeight = mHeight / 30.0f;
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        //初始化画笔
        LinePaint = new Paint();
        //去锯齿
        LinePaint.setAntiAlias(true);
        LinePaint.setColor(Color.WHITE);
        LinePaint.setStyle(Paint.Style.STROKE);
        LinePaint.setStrokeWidth(1);
        //初始化画笔
        TextPaint1 = new Paint();
        TextPaint1.setColor(Color.WHITE);
        TextPaint1.setTextSize(mTextSize);
        TextPaint1.setShader(null);
        //初始化画笔
        TextPaint = new Paint();
        TextPaint.setColor(Color.WHITE);
        TextPaint.setTextSize(mTextSize_ten);
        TextPaint.setShader(null);
        //初始化温度计的范围
        mRange = new RectF(0, 0, mWith, mHeight);
        isRunning = true;
        isRunning_kpa = true;
        mThread = new Thread(this);
        mThread.start();

    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

        isRunning = false;
        isRunning_kpa = false;

    }

    @Override
    public void run() {
        //不断进行绘制
        while (isRunning) {
            long start = System.currentTimeMillis();
            draw();
            long end = System.currentTimeMillis();
            if (end - start < everySecondTime) {
                //这里控制一下,一秒绘制二十次。也就是五十秒绘制一次
                try {
                    Thread.sleep(everySecondTime - (end - start));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void draw() {

        try {
            mCanvas = mHolder.lockCanvas();
            //这里要判断是不是为空,之因为在用户点击了home以后,可能已经执行到这里
            if (mCanvas != null) {
                //这里是开始绘制自己要的东西
                //先绘制背景,
                drawBg();
                //绘制水银的高度还有,显示体温
                drawShowHeightAndShow();
            }
        } catch (Exception e) {
            // e.printStackTrace();这里的异常不处理,
        } finally {
            if (mCanvas != null) {
                mHolder.unlockCanvasAndPost(mCanvas);
            }
        }

    }


    private void drawShowHeightAndShow() {
        float kpa = Targetlow_hight;
        float CurrentKpa = CurrentLow_hight;
        //这里控制水银的上升速度
        float difference = Math.abs(TargetTemperature - CurrentTemperature);
        float difference_kpa = Math.abs(kpa - CurrentKpa);
        /**
         * //这里定义一个boolean来控制是使用加法还是减法,其中true表示当前温度小于
         * 目标温度,要使用加法,false表示当前温度大于目标温度,要使用减法。
         */
        boolean addORsub = CurrentTemperature >= TargetTemperature ? false : true;
        boolean addOrsub_kpa = CurrentKpa >= kpa ? false : true;
        if (difference == 0 || difference <= 0.005) {
            mSpeed = 0;
            CurrentTemperature = TargetTemperature;
        } else {
            if (difference > 20) {
                mSpeed = (float) 0.5;
            } else {
                if (difference > 10) {
                    mSpeed = (float) 0.15;
                } else {
                    mSpeed = (float) 0.05;
                }
            }
        }
        if (difference_kpa == 0 || difference_kpa <= 0.005) {
            mSpeed_kpa = 0;
            CurrentKpa = kpa;
        } else {
            if (difference_kpa > 2) {
                mSpeed_kpa = (float) 0.6;
            } else {
                if (difference_kpa > 1) {
                    mSpeed_kpa = (float) 0.5;
                } else {
                    mSpeed_kpa = (float) 0.1;
                }
            }
        }
        if (addORsub) {
            CurrentTemperature += 20 * mSpeed;
        } else {
            CurrentTemperature -= 20 * mSpeed;
        }
        if (addOrsub_kpa) {
            CurrentKpa += 2 * mSpeed_kpa;
        } else {
            CurrentKpa -= 2 * mSpeed_kpa;
        }

        //

        Paint RightRectPaint = new Paint();
        RightRectPaint.setColor(Color.WHITE);
        RightRectPaint.setStyle(Paint.Style.FILL);
        Paint LeftRectPaint = new Paint();
        LeftRectPaint.setColor(Color.WHITE);
        LeftRectPaint.setStyle(Paint.Style.FILL);
        //这里主要是对温度的显示,画矩形的过程中,唯一改变的就是Top这一个值了
        //左侧水银柱
        if (Math.abs(CurrentTemperature - TargetTemperature) > 10) {
            float left = (temperatureAllLong / (left_temperatureRange * 1.0f)) * (int) (CurrentTemperature / 20) + (CurrentTemperature % 20) / 2 * (left_scaleLong);
            mCanvas.drawRect(centerWith - MercuryWith / 2, temperatureAllLong + abHeight * 2 - left, centerWith, temperatureAllLong + abHeight * 2, LeftRectPaint);
//            float right = (temperatureAllLong / (right_temperatureRange * 1.0f)) * (int) (CurrentKpa / 2) + (CurrentKpa % 2) / 2 * 4 * (right_scaleLong);
            float right = (temperatureAllLong / (left_temperatureRange * 1.0f)) * (int) (CurrentKpa / 20) + (CurrentKpa % 20) / 2 * (left_scaleLong);
            mCanvas.drawRect(centerWith + MercuryWith / 8, temperatureAllLong + abHeight * 2 - right, centerWith + MercuryWith / 2, temperatureAllLong + abHeight * 2, RightRectPaint);
            isRunning = true;
        } else {
            float left = (temperatureAllLong / (left_temperatureRange * 1.0f)) * (int) (TargetTemperature / 20) + (TargetTemperature % 20) / 2 * (left_scaleLong);
            mCanvas.drawRect(centerWith - MercuryWith / 2, temperatureAllLong + abHeight * 2 - left, centerWith, temperatureAllLong + abHeight * 2, LeftRectPaint);
//            float right = (temperatureAllLong / (right_temperatureRange * 1.0f)) * (int) (kpa / 2) + (kpa % 2) / 2 * 4 * (right_scaleLong);
            float right = (temperatureAllLong / (left_temperatureRange * 1.0f)) * (int) (kpa / 20) + (kpa % 20) / 2 * (left_scaleLong);
            mCanvas.drawRect(centerWith + MercuryWith / 8, temperatureAllLong + abHeight * 2 - right, centerWith + MercuryWith / 2, temperatureAllLong + abHeight * 2, RightRectPaint);
            isRunning = false;
        }
    }

    private void drawBg() {
        mCanvas.drawColor(getResources().getColor(R.color.class_blue));
        //画右边的刻度
        //定义每一个长刻度的高度
        float left_everyTemparaturHeight = temperatureAllLong / (left_temperatureRange * 1.0f);
        float right_everyTemparaturHeight = temperatureAllLong / (right_temperatureRange * 1.0f);
        mCanvas.drawLine(centerWith + MercuryWith / 2, abHeight * 2, centerWith + MercuryWith / 2, right_everyTemparaturHeight * 20 + abHeight * 2, LinePaint);
        for (int i = 0; i < right_temperatureRange; i++) {
            mCanvas.drawLine(centerWith + MercuryWith / 2, right_everyTemparaturHeight * i + abHeight * 2, centerWith + MercuryWith / 2 + MaxLineLong, right_everyTemparaturHeight * i + abHeight * 2, LinePaint);
            if (i == 0) {
                mCanvas.drawText(right_EndTenperature - i * 2 + "", centerWith + MercuryWith / 2 + MaxLineLong + MinLineLong / 3, right_everyTemparaturHeight * i + TextPaint1.getTextSize() / 2 + abHeight * 2, TextPaint1);
                mCanvas.drawText("Kpa", centerWith + MercuryWith / 2 + MaxLineLong + MinLineLong / 3 + 5, right_everyTemparaturHeight * i + TextPaint1.getTextSize() / 2 + abHeight * 2 + 15, TextPaint);
            } else {
                mCanvas.drawText(right_EndTenperature - i * 2 + "", centerWith + MercuryWith / 2 + MaxLineLong + MinLineLong / 3, right_everyTemparaturHeight * i + TextPaint1.getTextSize() / 2 + abHeight * 2, TextPaint1);
            }
            for (int j = 1; j < 5; j++) {
                mCanvas.drawLine(centerWith + MercuryWith / 2, right_everyTemparaturHeight * i + j * (right_scaleLong) + abHeight * 2, centerWith + MercuryWith / 2 + MinLineLong, right_everyTemparaturHeight * i + j * (right_scaleLong) + abHeight * 2, LinePaint);
            }
            //画最后一个刻度
            if (i == right_temperatureRange - 1) {

                mCanvas.drawLine(centerWith + MercuryWith / 2,
                        right_everyTemparaturHeight * (i + 1) + abHeight * 2,//这里加上两倍的上距离
                        centerWith + MercuryWith / 2 + MaxLineLong,
                        right_everyTemparaturHeight * (i + 1) + abHeight * 2, LinePaint);
                mCanvas.drawText(right_EndTenperature - (i + 1) * 2 + "", centerWith + MercuryWith / 2 + MaxLineLong + MinLineLong / 3,
                        right_everyTemparaturHeight * (i + 1) + TextPaint1.getTextSize() / 2 + abHeight * 2, TextPaint1);
            }
        }
        //画左边的刻度
        mCanvas.drawLine(centerWith - MercuryWith / 2, abHeight * 2, centerWith - MercuryWith / 2, left_everyTemparaturHeight * left_temperatureRange + abHeight * 2, LinePaint);
        for (int i = 0; i < left_temperatureRange; i++) {
            mCanvas.drawLine(centerWith - MercuryWith / 2, left_everyTemparaturHeight * i + abHeight * 2, centerWith - MercuryWith / 2 - MaxLineLong, left_everyTemparaturHeight * i + abHeight * 2, LinePaint);
            if (i == 0) {
                mCanvas.drawText(left_EndTenperature - i * 20 + "", centerWith - (MercuryWith / 2 + MaxLineLong + MinLineLong) - TextPaint1.getTextSize(), left_everyTemparaturHeight * i + TextPaint1.getTextSize() / 2 + abHeight * 2, TextPaint1);
                mCanvas.drawText("mmHg", centerWith - (MercuryWith / 2 + MaxLineLong + MinLineLong) - TextPaint1.getTextSize() + 5, left_everyTemparaturHeight * i + TextPaint1.getTextSize() / 2 + abHeight * 2 + 20, TextPaint);
            } else {
                mCanvas.drawText(left_EndTenperature - i * 20 + "", centerWith - (MercuryWith / 2 + MaxLineLong + MinLineLong) - TextPaint1.getTextSize(), left_everyTemparaturHeight * i + TextPaint1.getTextSize() / 2 + abHeight * 2, TextPaint1);
            }
            for (int j = 1; j <= 9; j++) {
                if (j == 5) {
                    mCanvas.drawLine(centerWith - MercuryWith / 2, left_everyTemparaturHeight * i + j * (left_scaleLong) + abHeight * 2, centerWith - MercuryWith / 2 - MidLineLong, left_everyTemparaturHeight * i + j * (left_scaleLong) + abHeight * 2, LinePaint);
                } else {
                    mCanvas.drawLine(centerWith - MercuryWith / 2, left_everyTemparaturHeight * i + j * (left_scaleLong) + abHeight * 2, centerWith - MercuryWith / 2 - MinLineLong, left_everyTemparaturHeight * i + j * (left_scaleLong) + abHeight * 2, LinePaint);
                }

            }
            //画最后一个刻度
            if (i == left_temperatureRange - 1) {
                mCanvas.drawLine(centerWith - MercuryWith / 2, left_everyTemparaturHeight * (i + 1) + abHeight * 2, centerWith - MercuryWith / 2 - MaxLineLong, left_everyTemparaturHeight * (i + 1) + abHeight * 2, LinePaint);
                mCanvas.drawText(left_EndTenperature - (i + 1) * 20 + "", centerWith - (MercuryWith / 2 + MaxLineLong + MinLineLong / 3) - TextPaint1.getTextSize(), left_everyTemparaturHeight * (i + 1) + TextPaint1.getTextSize() / 2 + abHeight * 2, TextPaint1);
            }
        }     
    }

    private float trueTemperature = 0;

    public void setTargetTemperature(float targetTemperature, float low_hight) {
        trueTemperature = targetTemperature;
        if (targetTemperature < 0) {
            targetTemperature = 0;
        }
        if (targetTemperature > left_EndTenperature) {
            targetTemperature = left_EndTenperature;
        }
        if (low_hight > left_EndTenperature) {
            low_hight = left_EndTenperature;
        }
        if (low_hight - targetTemperature > 10 && false) {
            TargetTemperature = targetTemperature;
            Targetlow_hight = targetTemperature + 10;
        } else {
            TargetTemperature = targetTemperature;
            Targetlow_hight = low_hight;
        }

        isRunning = true;
        draw();
    }

    public void setTargetTemperatureToZero() {
        TargetTemperature = 0;
        Targetlow_hight = 0;
        isRunning = true;
        run();
    }
}

用法:

            <view.Thermometer
            android:id = "@+id/thermometer"
            android:layout_width = "wrap_content"
            android:layout_height = "wrap_content" />
        thermometer = (Thermometer) view.findViewById(R.id.thermometer);
        thermometer.setZOrderOnTop(true);      // 这句不能少
        thermometer.setZOrderMediaOverlay(true);
        thermometer.getHolder().setFormat(PixelFormat.TRANSPARENT);

将控件放置顶部 如果不写这个,Fragment上面放置控件的时候 切换屏幕可能会导致控件不隐藏

常用方法:

    //将汞柱归零
    thermometer.setTargetTemperatureToZero();

这是单独开启的一个线程,会从当前温度降至最低点

    //输入数值 汞柱升高至对应数值 temp为左侧汞柱 temp_low_hight为右侧汞柱
    thermometer.setTargetTemperature(temp, temp_low_hight);

效果这个样子:
这里写图片描述

作者:jyww03 发表于2016/10/20 11:39:37 原文链接
阅读:15 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>