基于android平台的模拟血压计实现(surfaceView的熟练使用)
这个是我根据上一篇文章的温度计改的血压计,因为客户对温度计还有血压计的需求是一样的,所以,我就选择了偷懒,直接用温度计的代码改了一概,就成了血压计的了
1 package com.example.test; 2 3 4 5 import android.content.Context; 6 import android.graphics.Bitmap; 7 import android.graphics.Canvas; 8 import android.graphics.Color; 9 import android.graphics.Paint; 10 import android.graphics.RectF; 11 import android.util.AttributeSet; 12 import android.util.TypedValue; 13 import android.view.SurfaceHolder; 14 import android.view.SurfaceView; 15 16 17 18 19 import java.text.DecimalFormat; 20 21 /** 22 * Created by yinxiaofei on 2016/1/13. 23 */ 24 25 public class Sphygmomanometer extends SurfaceView implements SurfaceHolder.Callback ,Runnable{ 26 27 private SurfaceHolder mHolder; 28 private Canvas mCanvas; 29 30 //定义刻度的范围 31 int temperatureRange=5; 32 //定义一个盘快的范围 33 private RectF mRange=new RectF(); 34 //定义温度计的宽度和中心宽度 35 int mWith; 36 int mHeight; 37 int centerWith; 38 int centerHeight; 39 //定义总的宽度 40 41 //定义温度计刻度总长度 42 int temperatureAllLong; 43 44 //定义一下水银的宽度 45 int MercuryWith; 46 //十的倍数的线长度 47 int MaxLineLong; 48 //五的倍数的线的长度 49 int MidLineLong; 50 //其他刻度线的长度 51 int MinLineLong; 52 //刻度间隔 53 int scaleLong; 54 //定义温度计距离画布的上宽度 55 int abHeight; 56 57 //绘制线条的画笔 58 private Paint LinePaint; 59 //绘制文本的画笔 60 private Paint TextPaint; 61 62 //设置温度上升的速度 63 private volatile float mSpeed=0; 64 65 //设置背景图 66 private Bitmap mBitmap; 67 68 /** 69 * 定义初始温度,当前显示正在变化也就是显示的温度,还有目标温度 70 * 其中,初始温度不变, 71 * 当前温度是有程序根据不同的速度和目标温度计算出来的, 72 * 目标温度则是由仪器传送过来的数据 73 */ 74 private float BeginTenperature= (float) 0; 75 private int EndTenperrature=300; 76 private volatile float CurrentTemperature= (float) 60; 77 float TargetTemperature=120; 78 79 /** 80 * 定义每一秒绘制的次数 81 */ 82 int everySecondTime=50; 83 84 //设置文字的大小 85 private float mTextSize= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT,25,getResources().getDisplayMetrics()); 86 private float mSymbolTextSize= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT,35,getResources().getDisplayMetrics()); 87 private float mShowSymbolTextSize= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT,45,getResources().getDisplayMetrics()); 88 /** 89 * 用户绘制的线程 90 */ 91 private Thread mThread; 92 /** 93 * 根据目标温度改变要显示的当前温度的线程 94 */ 95 private Thread mChangeTemperatureThread; 96 97 /** 98 * 设置一个标志位,用于线程的开启还是关闭的标志 99 * @param context 100 */ 101 private Boolean isRunning; 102 private DecimalFormat fomat;//格式化float 103 104 public Sphygmomanometer(Context context) { 105 this(context, null); 106 } 107 108 public Sphygmomanometer(Context context, AttributeSet attrs) { 109 super(context,attrs); 110 mHolder=getHolder(); 111 mHolder.addCallback(this); 112 113 } 114 @Override 115 protected void onMeasure(int with,int height){ 116 super.onMeasure(with, height); 117 this.mWith=getMeasuredWidth()/2; 118 this.mHeight=getMeasuredHeight(); 119 //这里先把中心设置在屏幕的中心 120 this.centerWith=mWith/2; 121 this.centerHeight=mHeight/2; 122 //设置水银的宽度,暂时设置为总宽度的十五分之一 123 MercuryWith=mWith/15; 124 MinLineLong=MercuryWith; 125 MidLineLong=MinLineLong*8/5; 126 MaxLineLong=MidLineLong*3/2; 127 //temperatureAllLong表示温度刻度总长度 128 temperatureAllLong=mHeight*7/10; 129 //设置刻度间隔,包含了刻度线的长度 130 scaleLong=temperatureAllLong/temperatureRange/10;//表示一个温度十个刻度 131 132 133 abHeight=mHeight/10; 134 } 135 @Override 136 public void surfaceCreated(SurfaceHolder surfaceHolder) { 137 //初始化画笔 138 LinePaint=new Paint(); 139 //去锯齿 140 LinePaint.setAntiAlias(true); 141 LinePaint.setColor(Color.BLACK); 142 LinePaint.setStyle(Paint.Style.STROKE); 143 LinePaint.setStrokeWidth(1); 144 //初始化画笔 145 TextPaint=new Paint(); 146 TextPaint.setColor(Color.BLACK); 147 TextPaint.setTextSize(mTextSize); 148 TextPaint.setShader(null); 149 //初始化温度计的范围 150 mRange=new RectF(0,0,mWith,mHeight); 151 isRunning=true; 152 mThread =new Thread(this); 153 mThread.start(); 154 155 } 156 157 @Override 158 public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { 159 160 } 161 162 @Override 163 public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 164 165 isRunning=false; 166 167 } 168 169 @Override 170 public void run() { 171 //不断进行绘制 172 while(isRunning){ 173 long start=System.currentTimeMillis(); 174 draw(); 175 long end=System.currentTimeMillis(); 176 if(end-start<everySecondTime){ 177 //这里控制一下,一秒绘制二十次。也就是五十秒绘制一次 178 try { 179 Thread.sleep(everySecondTime-(end-start)); 180 } catch (InterruptedException e) { 181 e.printStackTrace(); 182 } 183 } 184 } 185 } 186 187 private void draw() { 188 189 try { 190 mCanvas=mHolder.lockCanvas(); 191 //这里要判断是不是为空,之因为在用户点击了home以后,可能已经执行到这里 192 if(mCanvas!=null) 193 { 194 //这里是开始绘制自己要的东西 195 //先绘制背景, 196 drawBg(); 197 //绘制水银的高度还有,显示体温 198 drawShowHeightAndShow(); 199 } 200 } catch (Exception e) { 201 // e.printStackTrace();这里的异常不处理, 202 } finally { 203 if(mCanvas!=null){ 204 mHolder.unlockCanvasAndPost(mCanvas); 205 } 206 } 207 208 } 209 210 private void drawShowHeightAndShow() { 211 212 //这里控制水银的上升速度 213 //这里要除以20,是因为血压计的刻度值,到温度计的刻度值,是二十倍的换算,主要是偷懒 214 float difference=Math.abs(TargetTemperature-CurrentTemperature)/60; 215 /** 216 * //这里定义一个boolean来控制是使用加法还是减法,其中true表示当前温度小于 217 * 目标温度,要使用加法,false表示当前温度大于目标温度,要使用减法。 218 */ 219 boolean addORsub=CurrentTemperature>=TargetTemperature?false:true; 220 if(difference==0||difference<=0.005){ 221 mSpeed=0; 222 CurrentTemperature=TargetTemperature; 223 }else{ 224 if (difference>2){ 225 mSpeed= (float) 0.03; 226 }else{ 227 if(difference>1){ 228 mSpeed= (float) 0.025; 229 }else{ 230 if(difference>0.5){ 231 mSpeed= (float) 0.015; 232 }else{ 233 if(difference>0.3){ 234 mSpeed= (float) 0.012; 235 }else{ 236 if(difference>0.2){ 237 mSpeed= (float) 0.009; 238 }else{ 239 mSpeed= (float) 0.008; 240 } 241 242 } 243 } 244 } 245 } 246 } 247 if(addORsub){ 248 CurrentTemperature+=mSpeed*100; 249 }else{ 250 CurrentTemperature-=mSpeed*100; 251 } 252 253 // 254 255 Paint RectPaint=new Paint(); 256 RectPaint.setStyle(Paint.Style.FILL); 257 // RectPaint.setColor(getResources().getColor(R.color.theme_color)); 258 // 这里主要是对温度的显示,画矩形的过程中,唯一改变的就是Top这一个值了 259 //这里(CurrentTemperature-BeginTenperature)/20表示的是刻度值的换算,从温度计过度到血压计的刻度值 260 if(Math.abs(CurrentTemperature-TargetTemperature)>0.8) 261 mCanvas.drawRect(centerWith-MercuryWith/2, 262 (scaleLong)*10*(temperatureRange)+abHeight*2- 263 (CurrentTemperature-BeginTenperature)/60*10*scaleLong, 264 centerWith+MercuryWith/2, 265 (scaleLong)*10*(temperatureRange)+abHeight*2, 266 RectPaint); 267 else{ 268 mCanvas.drawRect(centerWith-MercuryWith/2, 269 (scaleLong)*10*(temperatureRange)+abHeight*2- 270 (TargetTemperature-BeginTenperature)/60*10*scaleLong, 271 centerWith+MercuryWith/2, 272 (scaleLong)*10*(temperatureRange)+abHeight*2, 273 RectPaint); 274 } 275 276 //这里开始画显示的数字 277 Paint ShowNumberTextPaint=new Paint(); 278 ShowNumberTextPaint.setColor(Color.BLACK); 279 ShowNumberTextPaint.setTextSize(mShowSymbolTextSize); 280 ShowNumberTextPaint.setShader(null); 281 fomat = new DecimalFormat("##0.0"); 282 float display = Float.parseFloat(fomat.format(trueTemperature)); 283 mCanvas.drawText(display + " kpa", 284 mWith * 3 / 2 - ShowNumberTextPaint.getTextSize() * 2, 285 temperatureAllLong / 2 - ShowNumberTextPaint.getTextSize(), 286 ShowNumberTextPaint 287 ); 288 289 290 mCanvas.drawText(display + " kpa", 291 mWith*3/2- ShowNumberTextPaint.getTextSize() * 2, 292 temperatureAllLong/2+ShowNumberTextPaint.getTextSize(), 293 ShowNumberTextPaint 294 ); 295 296 } 297 298 private void drawBg() { 299 mCanvas.drawColor(Color.WHITE); 300 // mCanvas.drawLine(0, 0, mWith, mHeight, LinePaint); 301 //画右边的刻度 302 //定义每一个长刻度的高度 303 float everyTemparaturHeight=(scaleLong)*10; 304 for(int i=0;i<temperatureRange;i++){ 305 mCanvas.drawLine(centerWith + MercuryWith / 2, 306 everyTemparaturHeight * i + abHeight * 2,//这里加上两倍的上距离 307 centerWith + MercuryWith / 2 + MidLineLong, 308 everyTemparaturHeight * i + abHeight * 2, LinePaint); 309 for(int j=1;j<=9;j++){ 310 if(j==5){ 311 mCanvas.drawLine(centerWith+MercuryWith/2, 312 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2, 313 centerWith+MercuryWith/2+MaxLineLong, 314 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2,LinePaint); 315 mCanvas.drawText(EndTenperrature-30 - i * 60 + "", centerWith + MercuryWith / 2 + MaxLineLong + MinLineLong / 3, 316 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2 + TextPaint.getTextSize() / 2 , TextPaint); 317 }else{ 318 mCanvas.drawLine(centerWith+MercuryWith/2, 319 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2, 320 centerWith+MercuryWith/2+MinLineLong, 321 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2,LinePaint); 322 } 323 324 } 325 326 } 327 //画左边的刻度 328 for(int i=0;i<temperatureRange;i++){ 329 mCanvas.drawLine(centerWith-MercuryWith/2, 330 everyTemparaturHeight*i+abHeight*2, 331 centerWith-MercuryWith/2-MaxLineLong, 332 everyTemparaturHeight*i+abHeight*2,LinePaint); 333 if(EndTenperrature-i*60>99) 334 mCanvas.drawText(EndTenperrature-i*60+"", centerWith - (MercuryWith/2+MaxLineLong+MinLineLong/3)-TextPaint.getTextSize()*3/2, 335 everyTemparaturHeight * i + TextPaint.getTextSize() / 2+abHeight*2, TextPaint); 336 else if(EndTenperrature-i*60>9) 337 mCanvas.drawText(EndTenperrature-i*60+"", centerWith - (MercuryWith/2+MaxLineLong+MinLineLong/3)-TextPaint.getTextSize(), 338 everyTemparaturHeight * i + TextPaint.getTextSize() / 2+abHeight*2, TextPaint); 339 else if(EndTenperrature-i*60>=0) 340 mCanvas.drawText(EndTenperrature-i*60+"", centerWith - (MercuryWith/2+MaxLineLong+MinLineLong/3)-TextPaint.getTextSize()/100, 341 everyTemparaturHeight * i + TextPaint.getTextSize() / 2+abHeight*2, TextPaint); 342 343 for(int j=1;j<=9;j++){ 344 if(j==5){ 345 mCanvas.drawLine(centerWith-MercuryWith/2, 346 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2, 347 centerWith-MercuryWith/2-MidLineLong, 348 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2,LinePaint); 349 }else{ 350 mCanvas.drawLine(centerWith-MercuryWith/2, 351 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2, 352 centerWith-MercuryWith/2-MinLineLong, 353 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2,LinePaint); 354 } 355 356 } 357 //画最后一个刻度 358 if(i==temperatureRange-1){ 359 mCanvas.drawLine(centerWith-MercuryWith/2, 360 everyTemparaturHeight*(i+1)+abHeight*2, 361 centerWith-MercuryWith/2-MaxLineLong, 362 everyTemparaturHeight*(i+1)+abHeight*2,LinePaint); 363 mCanvas.drawText(EndTenperrature-(i+1)*60+"", centerWith - (MercuryWith/2+MaxLineLong+MinLineLong/3)-TextPaint.getTextSize(), 364 everyTemparaturHeight * (i+1) + TextPaint.getTextSize() / 2+abHeight*2, TextPaint); 365 } 366 } 367 //画红色的园 368 Paint CirclePaint=new Paint(); 369 CirclePaint.setStyle(Paint.Style.FILL); 370 // CirclePaint.setColor(getResources().getColor(R.color.theme_color)); 371 mCanvas.drawCircle(centerWith, 372 everyTemparaturHeight*(temperatureRange)+abHeight*2+MercuryWith, 373 MercuryWith*3/2,CirclePaint); 374 //画摄氏度的符号 375 Paint symbolTextPaint=new Paint(); 376 symbolTextPaint.setColor(Color.BLACK); 377 symbolTextPaint.setTextSize(mSymbolTextSize); 378 symbolTextPaint.setShader(null); 379 mCanvas.drawText("BP", 380 centerWith - MaxLineLong / 2 - MercuryWith / 2 - symbolTextPaint.getTextSize() / 2, 381 abHeight * 2 - symbolTextPaint.getTextSize(), 382 symbolTextPaint 383 ); 384 mCanvas.drawText("BP", 385 centerWith + MaxLineLong / 2 + MercuryWith / 2 - symbolTextPaint.getTextSize() / 2, 386 abHeight * 2 - symbolTextPaint.getTextSize(), 387 symbolTextPaint 388 ); 389 390 //绘制显示数字的符号和虚线 391 Paint ShowsymbolTextPaint=new Paint(); 392 ShowsymbolTextPaint.setColor(Color.BLACK); 393 ShowsymbolTextPaint.setTextSize(mShowSymbolTextSize); 394 ShowsymbolTextPaint.setShader(null); 395 396 mCanvas.drawText("- - - - - - - -", 397 mWith * 3 / 2 - ShowsymbolTextPaint.getTextSize() * 2, 398 temperatureAllLong/2, 399 ShowsymbolTextPaint 400 ); 401 402 } 403 404 private float trueTemperature = 0; 405 406 public void setTargetTemperature(float targetTemperature) { 407 trueTemperature = targetTemperature; 408 if(targetTemperature<0){ 409 targetTemperature = 0; 410 } 411 if(targetTemperature>EndTenperrature){ 412 targetTemperature = EndTenperrature; 413 } 414 TargetTemperature = targetTemperature; 415 } 416 }
至于xml的布局文件,请参考上一篇文章,其实也和简单