實戰酷斃了的自定義View(二)

Gtihub傳送門

Canvas的高級使用

在個人Github開源庫中,今天剛寫好了一個餅圖的繪製,這裏主要就是對餅圖繪製的一個講解了。ios

以前咱們講過了一個Path,可是若是全用Path去實現,也不是說不可以實現,可是並不適用於不少的場景狀況。git

這裏的話,咱們主要講的就是關於Canvas的使用了。以前咱們在Path中用到過這樣的一個函數moveTo,也就是把路徑從當前的位置移動到新的座標上。那咱們的Canvas是否有這樣的功能呢?github

天然是有的了,這裏直接做出一個解答,他的函數就是translate,可是有一點要注意!!!這個函數是一個相對移動,而不是絕對移動。canvas

canvas?.translate(60f, 80f)
paint?.let { canvas?.drawCircle(0f, 0f, 100f, it) }
canvas?.translate(60f, 80f)paint?.color = Color.BLUE
paint?.let { canvas?.drawCircle(0f, 0f, 100f, it) }
複製代碼

上述就是實現代碼以及一個貼圖了。你能夠直觀的感覺到這個移動實際上是基於當前的基礎來完成的。可是讀者會說了,這種效果徹底可讓我經過Path來完成啊,不必經過Canvas,ok,確實能夠,你也能夠經過Path來實現。函數

可是難點如今纔來,下圖的樣式該怎麼實現??工具

在知道怎麼寫代碼以前,那咱們要知道確定是他的組成成分究竟是什麼了。佈局

  1. 兩條線的組合。從直觀上就能夠看出,這個折線應該是兩條直線進行組合
  2. 兩行文字的組合。也就是圖片中的描述四和6.0%

若是讓咱們直接去獲取絕對座標,而後進行繪製,那是否是會很是麻煩呢?因此這裏要引入一個Canavs的操做方法。post

Canvas操做

在使用以前須要注意,畫布是須要保存的,否則畫布將不斷的保留上一次的狀態進行繪製,那總體就會呈現一種疊加混亂的局面。而這個方法就是save()restore()的成對使用。學習

for (i in 0..2) {
        canvas?.save()
        paint?.color = Color.BLUE
        canvas?.translate(60f, 80f)
        canvas?.scale(0.5f, 0.5f)
        paint?.let { canvas?.drawCircle(0f, 0f, 100f, it) }
        canvas?.restore()
    }
複製代碼
使用前 使用後

你能夠把這個操做理解爲畫布歸位,或者說畫布重置。而這個重置對應的就是保存了save()以前的操做過程。ui

Scale

這個效果再也不贅述了。

Rotate

和其餘的都是同樣的會有兩種畫布的操做函數

  1. rotate(float degrees, float px, float py),就是自定義旋轉圓心
  2. rotate(float degrees),畫布當前位置做爲旋轉圓心
canvas?.save()
paint?.color = Color.BLUE
canvas?.translate(60f, 80f)
canvas?.rotate(45f)
// 以自身中心做爲圓點旋轉
// canvas?.rotate(45f,30f, 40f)
paint?.let { canvas?.drawRect(0f, 0f, 100f, 100f, it) }
canvas?.restore()
複製代碼

餅圖的實現其實就是基於這個函數來完成的。

Shew

和其餘的不一樣了,他並再也不經過咱們的座標圓心,而是對標咱們XY

canvas?.save()
paint?.color = Color.BLUE
canvas?.translate(60f, 80f)
canvas?.skew(0f, 1f)
paint?.let { canvas?.drawRect(0f, 0f, 100f, 100f, it) }
canvas?.restore()
複製代碼

傳入的數據其實就是分別與XY軸的正切值,經過截圖工具,你可以明顯的發現這個問題。畫了綠色框框的部分,你能夠看到的是正好一個45度的大小。

經過畫圖你也能夠這樣理解,就是Y軸順時針方向旋轉45度。

餅圖繪製的基本思路

上面講過了畫布的一些基本操做,那咱們要具體講一下這個餅圖咱們該怎麼繪製了。講實話,我代碼裏已經基本註釋了,因此具體的以代碼爲準,這裏只作簡單的講解。幾個考慮部分:

  1. 圓和文字怎麼兼容,這是一個重難點,我也只能說經過屢次嘗試,到圓爲0.3倍的寬度最爲合適了。由於0.5倍,正好佔滿;0.4倍,文字過小。這個值你能夠自行作一個修改處理。
  2. 上面說過的介紹線怎麼畫。文字的的佈局確定直接根據介紹線來變更了,那這個介紹線就是相當重要的一點了。
  3. 弧形的顏色怎麼變換。

基本就是以上問題,問題1我已經作出來回答,後續兩個問題將一個個做出解釋。

介紹線怎麼畫

在個人代碼中,其實分爲兩塊,一是圓弧,一是介紹,這也是他們的繪製順序了。可是須要考慮一個問題:介紹線的位置肯定?

這個問題你須要看一下個人圖例了,你有沒有注意到,個人介紹線,好像都是關於單個圓弧居中的呢?

那咱們的方案其實就來了,上面咱們講到過了什麼?Rotate還記得這個函數嘛!!經過數據運算,有了每一個圓弧的大小,那咱們還不能去進行繪製嘛?不就是先劃線,再旋轉嗎。而後旋轉就是這樣的一個公式要去計算。

// 旋轉角度 = 前面的弧度 + 當前弧度的一半
private fun getRatioSum(j: Int): Float {
        var sum = 0f
        for (i in 0 until j) {
            sum += mRatios!![i]
        }
        return sum
    }

    private fun getRatioHalfSumDegrees(j: Int): Float {
        var sum = getRatioSum(j)
        sum += mRatios!![j] / 2
        return sum * 360
    }
複製代碼

弧形的顏色怎麼變換

跟前面的圓弧同樣,可是是一個個圓弧來組成圓,那這個時候,就是要知道前面的弧度,而後對當前的弧度的計算,也就是掃過的區間進行計算了。

private fun drawArc(canvas: Canvas) {
        val drawArc = 360 * scale
        for (i in mRatios!!.indices) {
            mArcPaint?.color = mArcColors!![i]
            mArcPaint?.let {
                canvas.drawArc(
                    arcRect!!,
                    getRatioSum(i) * drawArc,
                    mRatios!![i] * drawArc,
                    true,
                    it
                )
            }
        }
    }
複製代碼

基本上就是靠上述的兩個來完成的,是否是仍是比較簡單的呢。沖沖衝,Demo抄起來,你就有一份本身的餅圖繪製了。

以上就是個人學習成果,若是有什麼我沒有思考到的地方或是文章內存在錯誤,歡迎與我分享。


相關文章推薦:

實戰酷斃了的自定義View(一)

【從零衝擊音視頻開發】FFmpeg的介紹和基本使用

【從零衝擊音視頻開發】移動環境搭建

相關文章
相關標籤/搜索