效果这个样子:
由于项目需要,所以用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);12
作者:烤奶酪儿