1. 程式人生 > >自定義一個汽車時速表DashbordView

自定義一個汽車時速表DashbordView

先上個效果圖看下,按住加速按鈕不放,實現指標移動,並顯示當前的數值

鬆開手指,暫停加速。

思路:

1.畫個圓弧

2.畫100個小刻度

3.畫20個5分隔的中間刻度

4.畫10個小刻度

5.畫指標

6.畫刻度文字,當前刻度文字

7.實現動態指標變換

開始coding吧。

1.畫圓弧

canvas提供的畫弧形方法。

確定一個矩形的區域,初始角度,掃過的角度,是否使用中心(true扇形,false弧形),畫筆

ok,我們先來確定一下這個矩形怎麼放置

定義幾個引數

控制元件的寬高,圓形的半徑,

我們在onSizeChanged裡面先來定義這個矩形

矩形確定好了,那麼就去畫弧吧。

可是弧形有角度呢,怎麼算呢

這裡我們可以這樣來思考

我們可以設定一個初始的Angle,

那麼按照View的座標系,初始角度就是90°+(Angle / 2)

掃過的角度就是 360 - Angle

我們實驗一下,這裡我設定初始Angle 為120

 private static final int ANGLE = 120;


        mStartAngle = 90 + ANGLE / 2;
        mSweepAngle = 360 - ANGLE;

 

在onDraw中繪製

當然畫筆也是需要提前設定的

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.GREEN);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(Utils.dp2px(2));
canvas.drawArc(mArcRectF, mStartAngle, mSweepAngle, false, mPaint);

還不錯哦。符合預期效果

接下來畫格子吧

來介紹個類,PathDashPathEffect

構造的內容shape為一個path物件,可以理解為我們要畫的一個小線段的內容

advance表示間隙

phase表示第一個位置預留的空間

關於間隙,可以用PathMeasure去獲取我們之前新增的弧形,通過getLenght方法獲得弧形的長度

mArcPath.addArc(mArcRectF, mStartAngle, mSweepAngle);


mPathMeasure = new PathMeasure(mArcPath, false);

float length = mPathMeasure.getLength();

有了長度,我們就可以根據要劃分的個數來計算間隙了

但是這裡有個小提示

我們沒一個shape都是有寬度的,所以總體計算的長度,要減去一個shape的寬度

ok,我們先new出來

因為我們要劃分100個小單元,所以這裡的number是100

float v = length - Utils.dp2px(2);

shape = new Path();
shape.addRect(new RectF(0, 0, Utils.dp2px(2), Utils.dp2px(10)), Path.Direction.CW);
float advance = v / number;
float phase = 0;
mPathDashPathEffect = new PathDashPathEffect(shape, advance, phase, PathDashPathEffect.Style.ROTATE);

接著在ondraw中通過paint設定進來

看下效果,還可以哈

接下來就以此類推,畫出20個5分段的小個子

稍微區分一下,將shape調整長一點,畫筆也還是利用之前畫100個小段的,畢竟顏色都一直,僅僅是長度不一樣

然後再來畫10分段的長格子,這裡用一個新的畫筆,顏色設定為黑色進行區分

初具規模了,

繼續,畫文字

畫文字的方法呢,比較簡單,但是計算起來確實還是有點小繁瑣

你需要確定你的文字座標,即一個xy位置,

那麼我們想精確的在刻度上顯示這個文字怎麼去獲取刻度對應的座標呢

當然是sin 和cos了

還是這張圖,假設我想知道綠色線條終點的xy座標,怎麼算呢

x座標就是這條線段的長度 * cos(角度)

y座標同理,就是長度 * sin(角度)

我們先寫一個簡單的方法,來獲取刻度上對應的角度的方法

簡單想一下,假設現在的刻度是100,那麼最終算的的結果就是150+240=390,超出360的減去360,那麼就是30度

接下來畫文字其實就是for一個迴圈,每10個刻度畫一個文字

但是有個注意事項,文字是有高度的,所以想要文字看上去居中,我們要進行一些計算

獲取文字的最頂部位置和最底部位置 ,進行相加 / 2,就是文字在Y軸上的偏移量了,再繪製時講這個偏移減去即可

文字部分呢,我們也新定義一個畫筆

不要忘記加入相對位置

文字是相對於這個圓弧的中心的

執行下看看

剩下的畫實時速度的文字其實就很簡單了

Y方向,再中心位置向下偏移1/4個半徑的長度,看著還算ok

具體的畫筆程式碼就不貼了,就是居中啊,文字大小啊,文字顏色之類的了

畫指標

既然前面都已經知道怎麼去算文字的位置了,那麼指標的中心其實就是圓心了,那麼終點座標就很好計算了。

我們設定一個value,看看是否對應的上

private float mValue = 66;

符合預期

剩下的就是去動態的設定數值,核心就是改變value值,重繪

首先實現Runnable介面

重寫run方法

定義一個標識,如果start = true,就不停的加加value

重繪頁面

呼叫postInvalidate

為了不至於過快,再稍微延遲個50毫秒

最後就是到Activity中find出來這個View

new Thread(view) .start

好麼?其實也可以

我們來試試看

線性佈局,底部放一個button

設定button的touchListener 返回true,按下時,啟動執行緒,手指擡起時,終止執行緒

實際效果跟效果圖一樣,不演示了

之前我們在run方法裡列印了執行緒的資訊,其實也可以很只管的理解,畢竟每次都是在ontouch裡面new 出一個執行緒嗎

這樣我們可不喜歡,所以優化一下吧。

執行緒池

通過改變標記位就可以了

打印出來的執行緒資訊

當然其實也可以用之前的Thread start 方法,但是當手指擡起時,我們是要中斷執行緒,或者說是暫停執行緒

要麼interrupt,要麼wait,

那麼下次手指再次按下的時候,就需要去恢復執行緒,就不能使用start,否則會提示Thread is already start,

或者我們也可以用標識,第一次按下的時候,去start,後續按下僅僅改變標識位置也可以

像這樣,效果也是一樣的

記得在Activity 銷燬的時候終止執行緒哦

Thread 呼叫interrupt方法終止

Executors 呼叫shutdownNow

O了,就這樣吧,好久...........(*N)   沒寫部落格了,感覺就像流水賬一樣。

但大體思路應該表述清楚了吧???