基于android平台的模拟温度计测量实时温度的实现--(surfaceView的熟练使用)

上来老规矩,先上图,这个温度计是我为一个商用的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"
         />

 

posted @ 2016-06-08 23:42  晓风飞雨  阅读(4485)  评论(5编辑  收藏  举报