大家好,可能今年換了公司過得比較安逸,自己的心情也不算太好树瞭,所以一段時間都沒很好的學習和更新文章。自從最近看了扔物線HenCoder的文章之后同欠,自己感覺自己對很多自定義View和動畫的知識都不太懂,甚至在平時的開發(fā)極少用到,所以自己想好好學習這一塊的知識。之前無意中在公眾號上看到一個仿英雄聯(lián)盟的的七邊形戰(zhàn)力圖栏赴,自己發(fā)現(xiàn)蘑斧,平時我看的好幾個app都有這樣的多邊形戰(zhàn)力圖靖秩,所以覺得可以自己做一個大眾版的出來,適配各個關(guān)于多邊形戰(zhàn)力圖的自定義View竖瘾。下面我們看看效果圖:
然后再看看我自己寫的自定義View的效果:
可以看到其實大致的效果是差不多的沟突,但是有一些小細節(jié)可能需要自己去定制某個條件再處理,細化和潤色捕传,因為我這里是用同樣的方法惠拭,只是設(shè)置的參數(shù)不一樣,所以看上去有些細節(jié)需要再根據(jù)自己是幾邊形再調(diào)整一下。
大家看看我寫的代碼就知道了:
只需要短短的代碼就能畫出不同的戰(zhàn)力多邊形职辅。
好的棒呛,那下面我們就來講講這個東西是怎么實現(xiàn)的,老規(guī)矩域携,如果不想聽分析的同學可以直接下載源碼去看看簇秒。源碼下載鏈接
講代碼之前,先給大家講一下畫出這個多邊形的原理秀鞭,對趋观,就是數(shù)學原理,先看看下面的圖:
用一個正六邊形舉例锋边,假設(shè)說它每個角到坐標原點為半徑X皱坛,那么我們用數(shù)學的原理XcosA就能得出得出B點的X軸坐標,XsinA能得出B點的Y軸坐標豆巨,由此我們看出來B(XcosA剩辟,XsinA),至于∠A的度數(shù)怎么來的就更簡單了往扔,正n邊形360°/ n抹沪,即 2π/n 就能得到一個角是多少度的了。那很自然而然的瓤球,我們用一個for循環(huán)就可以得出六邊形所有的坐標點
for (i in 0..count - 1) {
//每個坐標點
(radius * cos(2 * Math.PI / count * i)).toFloat(), (radius * sin(2 * Math.PI / count * i)).toFloat())
}
以上就是多邊形戰(zhàn)力圖的數(shù)學原理融欧,應(yīng)該很簡單吧。其實很多自定義View也是一樣卦羡,只要懂了原理噪馏,很多東西很自然而然很簡單的就能寫出來。生活上很多事情也是一樣绿饵,沒做之前什么事情都想著自己做不好就放棄了欠肾,但是自己嘗試了發(fā)現(xiàn)原來這個事情原來那么簡單,我每次寫自定義View總有這個感慨拟赊。
不吹什么了刺桃,確實畢業(yè)一年多工作兩年最近感慨有點。好了吸祟,下面我們來看看代碼我是怎么一步步實現(xiàn)的吧瑟慈。在實現(xiàn)代碼之前,我先說這個View我是用kotlin寫的屋匕,最近也慢慢用kotlin寫代碼寫項目葛碧。一開始確實很不習慣,速度很慢过吻,但是我覺得我總會熟能生巧的吧进泼,所以貴在堅持嘛。
下面我們以懂球帝的六邊形戰(zhàn)力圖為例一步步畫出想要的效果吧:
一、首先我們需要畫出一個多邊形乳绕,和嵌套的多個多邊形绞惦。
代碼很簡單洋措,我們看看紅色框里面的代碼就是最核心的部分翩隧,一個for循環(huán),剛剛講原理的時候也說過呻纹。那下面詳細分析一下堆生,當i=0的時候,我們把path移動到我們的第一個點上雷酪,
path.moveTo((radius * cos(2 * Math.PI / count * i - Math.PI / 2)).toFloat(), (radius * sin(2 * Math.PI / count * i - Math.PI / 2)).toFloat())
當i>0的時候淑仆,我們就需要把這些點用路徑直線連起來了,所以用的是lineTo()
path.lineTo((radius * cos(2 * Math.PI / count * i - Math.PI / 2)).toFloat(), (radius * sin(2 * Math.PI / count * i - Math.PI / 2)).toFloat())
有人會問為什么角度最后需要減去π / 2哥力,那是因為我們需要把六邊形旋轉(zhuǎn)一下蔗怠,視覺效果更好。
一個六邊形我們畫出來了吩跋,那么一個六邊形里面多個嵌套的多邊形就能很容易的畫出來了寞射,只需要在第一個for循環(huán)的外面再加一個for循環(huán),每次把半徑都減去一定的值锌钮,那很簡單就畫出來了桥温。在上圖中紅色框框外的代碼做的事情就是去加一個for循環(huán),和給畫筆paint加上一些圖片的填充顏色梁丘,另外還在六邊形描了畫邊侵浸。
二、畫六邊形的中心到每個角的角邊:
有人注意到了嗎氛谜,我們在第一個for循環(huán)的時候加了一句代碼:
//把相應(yīng)的點保存到pointList中
points.add(PointF(radius * cos(2 * Math.PI / count * i - Math.PI / 2).toFloat(), radius * sin(2 * Math.PI / count * i - Math.PI / 2).toFloat()))
這句代碼就是把我們所要畫的六邊形的六個點的坐標保存了下來掏觉,為方便我們之后用,而且下面很多地方都用到了值漫,你看澳腹,這里就用到了。
我們這里考慮到有些多邊形不需要角邊杨何,所以加了一個判斷酱塔,不需要就設(shè)置false就好了。
畫完角邊我們就考慮一下多邊形外面的字體了晚吞。
三延旧、畫出字體
老實說,這里是我做這個自定義View最難受的地方槽地,因為字體的位置要根據(jù)六邊形每個角慢慢調(diào)整字體的不同的位置,我沒想到更好的辦法處理,暫時只是按照坐標軸的四個象限來稍微調(diào)整了一下位置捌蚊,所以當每個同學有興趣做定制化的時候集畅,需要自己再做一些細節(jié)的字體位置調(diào)整處理。
畫完六邊形外面的內(nèi)容缅糟,那么我們就要往里看看了吧挺智。
四、畫出分數(shù)區(qū)域及設(shè)置相關(guān)屬性
1.我們要設(shè)置分數(shù)區(qū)域的一些屬性窗宦,另它更好看一點:
2.設(shè)置各個屬性的分數(shù)比例:
3.按比例畫出每個區(qū)域的點并連成線:
其實這一步跟第一步很類似赦颇,也并沒有什么難點可言。
最后我們來看看最終的效果圖:
講完多邊形戰(zhàn)力圖的原理代碼赴涵,我們再看看要如何使用:
關(guān)于使用媒怯,我用了設(shè)計模式的builder模式,即建造者模式來管理整個自定義View的配置髓窜。我把每個屬性都分開做定制化處理扇苞,并連成一條數(shù)據(jù)鏈初始化,然后最后調(diào)用build的方法就可以實現(xiàn)所有方法的配置寄纵,是不是很簡便鳖敷,雖然代碼量多了,但是builder模式對我以后對這個自定義View的修改和擴展非常有好處程拭。
下面講講做這個自定義View在kotlin上遇到的一些小問題:
1.構(gòu)造函數(shù)的編寫跟java有區(qū)別:
有人注意到了嗎定踱,雖然在意思上是一樣的,但是kotlin和java在表達上在構(gòu)造函數(shù)這塊上可有不一樣的地方恃鞋。
2.kotlin的小坑:
誰都知道屋吨,kotlin是不需要在代碼中初始化xml控件的,這一點用過的人都會覺得很方便山宾,但是在這里我踩了一個小坑至扰,看下圖:
大家是不是會覺得這段代碼完全沒問題?我一開始也是這么認為的资锰,但是我得到的結(jié)果是敢课。。绷杜。直秆。。
為什么說我沒有初始化呢鞭盟,明明代碼的編譯成功了圾结,我一開始想不明白為什么,后來經(jīng)過一個師兄的提醒 齿诉,我才發(fā)現(xiàn)我們在聲明的時候筝野,dongqiudiPolygonView指向的只是一個int類型的數(shù)字晌姚,但是如果你想用他的build方法,你還是要老老實實的加上一句
dongqiudiPolygonView = findViewById(R.id.dongqiudiPolygonView)
哎歇竟,坑啊挥唠,所以說探索還是需要有點代價的,下次就不會再犯這種低級錯誤了焕议。
好了宝磨,這一期就講得差不多了,如果對我的代碼有什么建議的同學可以跟我討論一下盅安,譬如說很多kotlin的問題我自己都沒搞得懂~對我的項目有興趣的同學可以下載我的源碼一起學習和交流唤锉,共同進步!源碼下載鏈接