Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 自定義View——模擬水銀柱

自定義View——模擬水銀柱

編輯:關於Android編程

由於項目需要,所以用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();
    }
}

用法:

            
        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);

效果這個樣子:
這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved