上來老規矩,先上圖,這個溫度計是我為一個商用的app專門開發的,商業原因,其他的截圖還有代碼不可以公布,但是這個溫度計的源碼是可以公布的,這個代碼是我自己精心設計的,里面有不少的計算公式,感覺自己還是設計的很巧妙的模擬也很逼真,尤其是在測量溫度的時候,溫度計水銀的高度變化,這個是要用有一個速度來控制的,尤其是這個溫度的變化還是實時的,也是不可控的,所以我們要考慮到溫度的隨時變化,根據當前的目標溫度還有當前水銀柱的高度,老確定當前的水銀上升速度是多少。當然了這只是一個方面,還有其他的,比如字體的大小還有刻度的長度,這些全部都是要根據畫布的大小來變化的,這個在我的代碼中也有體現。下面這個類的代碼可以直接通過最后一個函數setTargetTemperature調用,設置實時的溫度,溫度計會顯示出來實時的變化。希望大家可以用到。
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 import java.text.DecimalFormat; 19 20 /** 21 * Created by yinxiaofei on 2016/1/13. 22 */ 23 24 public class Thermometer extends SurfaceView implements SurfaceHolder.Callback ,Runnable{ 25 26 private SurfaceHolder mHolder; 27 private Canvas mCanvas; 28 29 //定義溫度的范圍 30 int temperatureRange=12; 31 //定義一個盤快的范圍 32 private RectF mRange=new RectF(); 33 //定義溫度計的寬度和中心寬度 34 int mWith; 35 int mHeight; 36 int centerWith; 37 int centerHeight; 38 //定義總的寬度 39 40 //定義溫度計刻度總長度 41 int temperatureAllLong; 42 43 //定義一下水銀的寬度 44 int MercuryWith; 45 //十的倍數的線長度 46 int MaxLineLong; 47 //五的倍數的線的長度 48 int MidLineLong; 49 //其他刻度線的長度 50 int MinLineLong; 51 //刻度間隔 52 int scaleLong; 53 //定義溫度計距離畫布的上寬度 54 int abHeight; 55 56 //繪制線條的畫筆 57 private Paint LinePaint; 58 //繪制文本的畫筆 59 private Paint TextPaint; 60 61 //設置溫度上升的速度 62 private volatile float mSpeed=0; 63 64 //設置背景圖 65 private Bitmap mBitmap; 66 67 /** 68 * 定義初始溫度,當前顯示正在變化也就是顯示的溫度,還有目標溫度 69 * 其中,初始溫度不變, 70 * 當前溫度是有程序根據不同的速度和目標溫度計算出來的, 71 * 目標溫度則是由儀器傳送過來的數據 72 */ 73 private float BeginTenperature= (float) 30; 74 private int EndTenperature=42; 75 private volatile float CurrentTemperature= (float) 30; 76 77 78 79 float TargetTemperature=39; 80 81 /** 82 * 定義每一秒繪制的次數 83 */ 84 int everySecondTime=100; 85 86 //設置文字的大小 87 private float mTextSize= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT,25,getResources().getDisplayMetrics()); 88 private float mSymbolTextSize= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT,35,getResources().getDisplayMetrics()); 89 private float mShowSymbolTextSize= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SHIFT,45,getResources().getDisplayMetrics()); 90 /** 91 * 用戶繪制的線程 92 */ 93 private Thread mThread; 94 /** 95 * 根據目標溫度改變要顯示的當前溫度的線程 96 */ 97 private Thread mChangeTemperatureThread; 98 99 /** 100 * 設置一個標志位,用於線程的開啟還是關閉的標志 101 * @param context 102 */ 103 private Boolean isRunning; 104 105 private DecimalFormat fomat;//格式化float 106 107 public Thermometer(Context context) { 108 this(context, null); 109 } 110 111 public Thermometer(Context context, AttributeSet attrs) { 112 super(context,attrs); 113 mHolder=getHolder(); 114 mHolder.addCallback(this); 115 116 } 117 @Override 118 protected void onMeasure(int with,int height){ 119 super.onMeasure(with, height); 120 this.mWith=getMeasuredWidth()/2; 121 this.mHeight=getMeasuredHeight(); 122 //這里先把中心設置在屏幕的中心 123 this.centerWith=mWith/2; 124 this.centerHeight=mHeight/2; 125 //設置水銀的寬度,暫時設置為總寬度的十五分之一 126 MercuryWith=mWith/15; 127 MinLineLong=MercuryWith; 128 MidLineLong=MinLineLong*8/5; 129 MaxLineLong=MidLineLong*3/2; 130 //temperatureAllLong表示溫度刻度總長度 131 temperatureAllLong=mHeight*7/10; 132 //設置刻度間隔,包含了刻度線的長度 133 scaleLong=temperatureAllLong/temperatureRange/10;//表示一個溫度十個刻度 134 135 136 abHeight=mHeight/12; 137 } 138 @Override 139 public void surfaceCreated(SurfaceHolder surfaceHolder) { 140 //初始化畫筆 141 LinePaint=new Paint(); 142 //去鋸齒 143 LinePaint.setAntiAlias(true); 144 LinePaint.setColor(Color.BLACK); 145 LinePaint.setStyle(Paint.Style.STROKE); 146 LinePaint.setStrokeWidth(1); 147 //初始化畫筆 148 TextPaint=new Paint(); 149 TextPaint.setColor(Color.BLACK); 150 TextPaint.setTextSize(mTextSize); 151 TextPaint.setShader(null); 152 //初始化溫度計的范圍 153 mRange=new RectF(0,0,mWith,mHeight); 154 isRunning=true; 155 mThread =new Thread(this); 156 mThread.start(); 157 158 } 159 160 @Override 161 public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { 162 163 } 164 165 @Override 166 public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 167 168 isRunning=false; 169 170 } 171 172 @Override 173 public void run() { 174 //不斷進行繪制 175 while(isRunning){ 176 long start=System.currentTimeMillis(); 177 draw(); 178 long end=System.currentTimeMillis(); 179 if(end-start<everySecondTime){ 180 //這里控制一下,一秒繪制二十次。也就是五十秒繪制一次 181 try { 182 Thread.sleep(everySecondTime-(end-start)); 183 } catch (InterruptedException e) { 184 e.printStackTrace(); 185 } 186 } 187 } 188 } 189 190 private void draw() { 191 192 try { 193 mCanvas=mHolder.lockCanvas(); 194 //這里要判斷是不是為空,之因為在用戶點擊了home以后,可能已經執行到這里 195 if(mCanvas!=null) 196 { 197 //這里是開始繪制自己要的東西 198 //先繪制背景, 199 drawBg(); 200 //繪制水銀的高度還有,顯示體溫 201 drawShowHeightAndShow(); 202 } 203 } catch (Exception e) { 204 // e.printStackTrace();這里的異常不處理, 205 } finally { 206 if(mCanvas!=null){ 207 mHolder.unlockCanvasAndPost(mCanvas); 208 } 209 } 210 211 } 212 213 private void drawShowHeightAndShow() { 214 215 //這里控制水銀的上升速度 216 float difference=Math.abs(TargetTemperature-CurrentTemperature); 217 /** 218 * //這里定義一個boolean來控制是使用加法還是減法,其中true表示當前溫度小於 219 * 目標溫度,要使用加法,false表示當前溫度大於目標溫度,要使用減法。 220 */ 221 boolean addORsub=CurrentTemperature>=TargetTemperature?false:true; 222 if(difference==0||difference<=0.005){ 223 mSpeed=0; 224 CurrentTemperature=TargetTemperature; 225 }else{ 226 if (difference>2){ 227 mSpeed= (float) 0.03; 228 }else{ 229 if(difference>1){ 230 mSpeed= (float) 0.025; 231 }else{ 232 if(difference>0.5){ 233 mSpeed= (float) 0.015; 234 }else{ 235 if(difference>0.3){ 236 mSpeed= (float) 0.012; 237 }else{ 238 if(difference>0.2){ 239 mSpeed= (float) 0.009; 240 }else{ 241 mSpeed= (float) 0.008; 242 } 243 244 } 245 } 246 } 247 } 248 } 249 if(addORsub){ 250 CurrentTemperature+=20*mSpeed; 251 }else{ 252 CurrentTemperature-=20*mSpeed; 253 } 254 255 // 256 257 Paint RectPaint=new Paint(); 258 RectPaint.setStyle(Paint.Style.FILL); 259 // RectPaint.setColor(getResources().getColor(R.color.theme_color)); 260 // 這里主要是對溫度的顯示,畫矩形的過程中,唯一改變的就是Top這一個值了 261 if(Math.abs(CurrentTemperature-TargetTemperature)>0.32) 262 mCanvas.drawRect(centerWith-MercuryWith/2, 263 (scaleLong)*10*(temperatureRange)+abHeight*2- 264 (CurrentTemperature-BeginTenperature)*10*scaleLong, 265 centerWith+MercuryWith/2, 266 (scaleLong)*10*(temperatureRange)+abHeight*2, 267 RectPaint); 268 else{ 269 mCanvas.drawRect(centerWith-MercuryWith/2, 270 (scaleLong)*10*(temperatureRange)+abHeight*2- 271 (TargetTemperature-BeginTenperature)*10*scaleLong, 272 centerWith+MercuryWith/2, 273 (scaleLong)*10*(temperatureRange)+abHeight*2, 274 RectPaint); 275 } 276 277 //這里開始畫顯示的數字 278 Paint ShowNumberTextPaint=new Paint(); 279 ShowNumberTextPaint.setColor(Color.BLACK); 280 ShowNumberTextPaint.setTextSize(mShowSymbolTextSize); 281 ShowNumberTextPaint.setShader(null); 282 fomat = new DecimalFormat("##0.0"); 283 float display = Float.parseFloat(fomat.format(trueTemperature)); 284 mCanvas.drawText(display + "", 285 mWith * 3 / 2 - ShowNumberTextPaint.getTextSize() * 2, 286 temperatureAllLong / 2 - ShowNumberTextPaint.getTextSize(), 287 ShowNumberTextPaint 288 ); 289 mCanvas.drawText(display + "", 290 mWith*3/2- ShowNumberTextPaint.getTextSize() * 2, 291 temperatureAllLong/2+ShowNumberTextPaint.getTextSize(), 292 ShowNumberTextPaint 293 ); 294 295 } 296 297 private void drawBg() { 298 mCanvas.drawColor(Color.WHITE); 299 // mCanvas.drawLine(0, 0, mWith, mHeight, LinePaint); 300 //畫右邊的刻度 301 //定義每一個長刻度的高度 302 float everyTemparaturHeight=(scaleLong)*10; 303 for(int i=0;i<temperatureRange;i++){ 304 mCanvas.drawLine(centerWith+MercuryWith/2, 305 everyTemparaturHeight*i+abHeight*2,//這里加上兩倍的上距離 306 centerWith+MercuryWith/2+MaxLineLong, 307 everyTemparaturHeight*i+abHeight*2,LinePaint); 308 mCanvas.drawText(EndTenperature-i+"",centerWith+MercuryWith/2+MaxLineLong+MinLineLong/3, 309 everyTemparaturHeight*i+TextPaint.getTextSize()/2+abHeight*2,TextPaint); 310 for(int j=1;j<=9;j++){ 311 if(j==5){ 312 mCanvas.drawLine(centerWith+MercuryWith/2, 313 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2, 314 centerWith+MercuryWith/2+MidLineLong, 315 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2,LinePaint); 316 }else{ 317 mCanvas.drawLine(centerWith+MercuryWith/2, 318 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2, 319 centerWith+MercuryWith/2+MinLineLong, 320 everyTemparaturHeight*i+j*(scaleLong)+abHeight*2,LinePaint); 321 } 322 323 } 324 //畫最后一個刻度 325 if(i==temperatureRange-1){ 326 327 mCanvas.drawLine(centerWith+MercuryWith/2, 328 everyTemparaturHeight*(i+1)+abHeight*2,//這里加上兩倍的上距離 329 centerWith+MercuryWith/2+MaxLineLong, 330 everyTemparaturHeight*(i+1)+abHeight*2,LinePaint); 331 mCanvas.drawText(EndTenperature-(i+1)+"",centerWith+MercuryWith/2+MaxLineLong+MinLineLong/3, 332 everyTemparaturHeight*(i+1)+TextPaint.getTextSize()/2+abHeight*2,TextPaint); 333 } 334 } 335 //畫左邊的刻度 336 for(int i=0;i<temperatureRange;i++){ 337 mCanvas.drawLine(centerWith-MercuryWith/2, 338 everyTemparaturHeight*i+abHeight*2, 339 centerWith-MercuryWith/2-MaxLineLong, 340 everyTemparaturHeight*i+abHeight*2,LinePaint); 341 mCanvas.drawText(EndTenperature-i+"", centerWith - (MercuryWith/2+MaxLineLong+MinLineLong/3)-TextPaint.getTextSize(), 342 everyTemparaturHeight * i + TextPaint.getTextSize() / 2+abHeight*2, TextPaint); 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(EndTenperature-(i+1)+"", 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("℃", 380 centerWith - MaxLineLong / 2 - MercuryWith / 2 - symbolTextPaint.getTextSize() / 2, 381 abHeight * 2 - symbolTextPaint.getTextSize(), 382 symbolTextPaint 383 ); 384 mCanvas.drawText("℃", 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 mCanvas.drawText("℃", 396 mWith*3/2, 397 temperatureAllLong/2-ShowsymbolTextPaint.getTextSize(), 398 ShowsymbolTextPaint 399 ); 400 mCanvas.drawText("- - - - - - - -", 401 mWith+ShowsymbolTextPaint.getTextSize()*3, 402 temperatureAllLong/2, 403 ShowsymbolTextPaint 404 ); 405 mCanvas.drawText("℃", 406 mWith*3/2, 407 temperatureAllLong/2+ShowsymbolTextPaint.getTextSize(), 408 ShowsymbolTextPaint 409 ); 410 411 } 412 413 private float trueTemperature =0 ; 414 415 public void setTargetTemperature(float targetTemperature) { 416 trueTemperature = targetTemperature; 417 if(targetTemperature<30){ 418 targetTemperature = 30; 419 } 420 if(targetTemperature>EndTenperature){ 421 targetTemperature = EndTenperature; 422 } 423 TargetTemperature = targetTemperature; 424 } 425 }
布局文件直接在你的xml當中添加以下語句就可以了
<com.example.test.Sphygmomanometer android:layout_width="wrap_content" android:layout_height="wrap_content" />