Android RadarView雷達(dá)圖(蜘蛛網(wǎng)圖)的實(shí)現(xiàn)代碼
無(wú)圖言虛空
簡(jiǎn)單分析一波,確定雷達(dá)圖正幾邊形的--正五邊形 int count=5,分為幾個(gè)層數(shù)--4 層 int layerCount=4
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawPolygon(canvas);//畫(huà)邊 drawLines(canvas);//畫(huà)線 drawText(canvas);//描繪文字 drawRegion(canvas);//覆蓋區(qū)域 }
主要這幾步,開(kāi)擼!
自定義RadarView繼承View
確定需要使用的變量,初始化paint,計(jì)算圓心角
private int count = 5; //幾邊形 private int layerCount = 4; //層數(shù) private float angle; //每條邊對(duì)應(yīng)的圓心角 private int centerX; //圓心x private int centerY; //圓心y private float radius; //半徑 private Paint polygonPaint; //邊框paint private Paint linePaint; //連線paint private Paint txtPaint; //文字paint private Paint circlePaint; //圓點(diǎn)paint private Paint regionColorPaint; //覆蓋區(qū)域paint private Double[] percents = {0.91, 0.35, 0.12, 0.8, 0.5}; //覆蓋區(qū)域百分比 private String[] titles = {"dota", "斗地主", "大吉大利,晚上吃雞", "爐石傳說(shuō)", "跳一跳"};//文字
public RadarView(Context context) { this(context, null, 0); } public RadarView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public RadarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //計(jì)算圓心角 angle = (float) (Math.PI * 2 / count); polygonPaint = new Paint(); polygonPaint.setColor(ContextCompat.getColor(context, R.color.radarPolygonColor)); polygonPaint.setAntiAlias(true); polygonPaint.setStyle(Paint.Style.STROKE); polygonPaint.setStrokeWidth(4f); linePaint = new Paint(); linePaint.setColor(ContextCompat.getColor(context, R.color.radarLineColor)); linePaint.setAntiAlias(true); linePaint.setStyle(Paint.Style.STROKE); linePaint.setStrokeWidth(2f); txtPaint = new Paint(); txtPaint.setColor(ContextCompat.getColor(context, R.color.radarTxtColor)); txtPaint.setAntiAlias(true); txtPaint.setStyle(Paint.Style.STROKE); txtPaint.setTextSize(DensityUtil.dpToPx(context, 12)); circlePaint = new Paint(); circlePaint.setColor(ContextCompat.getColor(context, R.color.radarCircleColor)); circlePaint.setAntiAlias(true); regionColorPaint = new Paint(); regionColorPaint.setColor(ContextCompat.getColor(context, R.color.radarRegionColor)); regionColorPaint.setStyle(Paint.Style.FILL); regionColorPaint.setAntiAlias(true); }
確定中心點(diǎn)
需要正五邊形得有一個(gè)圓,圓內(nèi)接正五邊形,在onSizeChanged方法里獲取圓心,確定半徑
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); radius = Math.min(h, w) / 2 * 0.7f; centerX = w / 2; centerY = h / 2; }
繪制正五邊形
繪制正五邊形同時(shí)描繪最外圍的點(diǎn),確定分為4層,半徑 / 層數(shù) =每層之間的間距,從最里層開(kāi)始畫(huà)正五邊形,每層第一個(gè)點(diǎn)位于中心點(diǎn)正上方
private void drawPolygon(Canvas canvas) { Path path = new Path(); float r = radius / layerCount; for (int i = 1; i <= layerCount; i++) { float curR = r * i; //當(dāng)前所在層的半徑 for (int j = 0; j < count; j++) { if (j == 0) { //每一層第一個(gè)點(diǎn)坐標(biāo) path.moveTo(centerX, centerY - curR); } else { //順時(shí)針記錄其余頂角的點(diǎn)坐標(biāo) float x = (float) (centerX + Math.sin(angle * j) * curR); float y = (float) (centerY - Math.cos(angle * j) * curR); path.lineTo(x, y); } } //最外層的頂角外面的五個(gè)小圓點(diǎn)(圖中紅色部分) if (i == layerCount) { for (int j = 0; j < count; j++) { float x = (float) (centerX + Math.sin(angle * j) * (curR + 12)); float y = (float) (centerY - Math.cos(angle * j) * (curR + 12)); canvas.drawCircle(x, y, 4, circlePaint); } } path.close(); canvas.drawPath(path, polygonPaint); } }
繪制連線
繪制最內(nèi)層頂角到最外層頂角的連線
private void drawLines(Canvas canvas) { float r = radius / layerCount; for (int i = 0; i < count; i++) { //起始坐標(biāo) 從中心開(kāi)始的話(huà) startx=centerX , startY=centerY float startX = (float) (centerX + Math.sin(angle * i) * r); float startY = (float) (centerY - Math.cos(angle * i) * r); //末端坐標(biāo) float endX = (float) (centerX + Math.sin(angle * i) * radius); float endY = (float) (centerY - Math.cos(angle * i) * radius); canvas.drawLine(startX, startY, endX, endY, linePaint); } }
至此簡(jiǎn)易雷達(dá)圖成型,可以修改正幾邊形,多少層數(shù)(后續(xù)繼續(xù)添加文字)
//設(shè)置幾邊形,**注意:設(shè)置幾邊形需要重新計(jì)算圓心角** public void setCount(int count){ this.count = count; angle = (float) (Math.PI * 2 / count); invalidate(); } //設(shè)置層數(shù) public void setLayerCount(int layerCount){ this.layerCount = layerCount; invalidate(); }
設(shè)置正六邊形、六層
radarView.setCount(6); radarView.setLayerCount(6);
對(duì)于以下圖形的,可以設(shè)置第一個(gè)點(diǎn)坐標(biāo)位于中心點(diǎn)正右側(cè) (centerX+curR,centerY)
,順時(shí)針計(jì)算其余頂點(diǎn)坐標(biāo) x = (float) (centerX+curR*Math.cos(angle*j)), y = (float) (centerY+curR*Math.sin(angle*j))
,同理連線等其余坐標(biāo)相應(yīng)改變...
描繪文字
由于各產(chǎn)品維度內(nèi)容不同,所需雷達(dá)圖樣式不一,這里只是描繪下不同位置的文字處理情況,具體需求還得按產(chǎn)品來(lái),因產(chǎn)品而異
private void drawText(Canvas canvas) { for (int i = 0; i < count; i++) { //獲取到雷達(dá)圖最外邊的坐標(biāo) float x = (float) (centerX + Math.sin(angle * i) * (radius + 12)); float y = (float) (centerY - Math.cos(angle * i) * (radius + 12)); if (angle * i == 0) { //第一個(gè)文字位于頂角正上方 txtPaint.setTextAlign(Paint.Align.CENTER); canvas.drawText(titles[i], x, y - 18, txtPaint); txtPaint.setTextAlign(Paint.Align.LEFT); } else if (angle * i > 0 && angle * i < Math.PI / 2) { //微調(diào) canvas.drawText(titles[i], x + 18, y + 10, txtPaint); } else if (angle * i >= Math.PI / 2 && angle * i < Math.PI) { //最右下的文字獲取到文字的長(zhǎng)、寬,按文字長(zhǎng)度百分比向左移 String txt = titles[i]; Rect bounds = new Rect(); txtPaint.getTextBounds(txt, 0, txt.length(), bounds); float height = bounds.bottom - bounds.top; float width = txtPaint.measureText(txt); canvas.drawText(txt, x - width * 0.4f, y + height + 18, txtPaint); } else if (angle * i >= Math.PI && angle * i < 3 * Math.PI / 2) { //同理最左下的文字獲取到文字的長(zhǎng)、寬,按文字長(zhǎng)度百分比向左移 String txt = titles[i]; Rect bounds = new Rect(); txtPaint.getTextBounds(txt, 0, txt.length(), bounds); float width = txtPaint.measureText(txt); float height = bounds.bottom - bounds.top; canvas.drawText(txt, x - width * 0.6f, y + height + 18, txtPaint); } else if (angle * i >= 3 * Math.PI / 2 && angle * i < 2 * Math.PI) { //文字向左移動(dòng) String txt = titles[i]; float width = txtPaint.measureText(txt); canvas.drawText(txt, x - width - 18, y + 10, txtPaint); } } }
繪制覆蓋區(qū)域
繪制覆蓋區(qū)域,百分比取連線長(zhǎng)度的百分比(如果從中心點(diǎn)開(kāi)始的連線,則是半徑的百分比),此處用半徑radius減去間隔r即連線長(zhǎng)度
private void drawRegion(Canvas canvas) { Path path = new Path(); float r = radius / layerCount;//每層的間距 for (int i = 0; i < count; i++) { if (i == 0) { path.moveTo(centerX, (float) (centerY - r - (radius - r) * percents[i])); } else { float x = (float) (centerX + Math.sin(angle * i) * (percents[i] * (radius - r) + r)); float y = (float) (centerY - Math.cos(angle * i) * (percents[i] * (radius - r) + r)); path.lineTo(x, y); } } path.close(); canvas.drawPath(path, regionColorPaint); }
至此,一個(gè)簡(jiǎn)單的雷達(dá)圖完畢。以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android ActionBar完全解析使用官方推薦的最佳導(dǎo)航欄(上)
Action Bar是一種新増的導(dǎo)航欄功能,在Android 3.0之后加入到系統(tǒng)的API當(dāng)中,它標(biāo)識(shí)了用戶(hù)當(dāng)前操作界面的位置,并提供了額外的用戶(hù)動(dòng)作、界面導(dǎo)航等功能2017-04-04Android控件AppWidgetProvider使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android控件AppWidgetProvider的使用方法詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08Android利用DownloadManager實(shí)現(xiàn)文件下載
這篇文章主要為大家詳細(xì)介紹了Android利用DownloadManager實(shí)現(xiàn)文件下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08簡(jiǎn)單談?wù)刟ndroid studio 的單元測(cè)試
昨天在完善項(xiàng)目的時(shí)候,需要進(jìn)行單元測(cè)試,在Eclipse環(huán)境中進(jìn)行是很簡(jiǎn)單的,但是在Android Studio環(huán)境中進(jìn)行單元測(cè)試,在國(guó)內(nèi)找了很多資料,大都是人云亦云,本文發(fā)布出來(lái)供大家學(xué)習(xí)參考。2016-08-08Android入門(mén)之ListView應(yīng)用解析(一)
這篇文章主要介紹了Android入門(mén)之ListView應(yīng)用,簡(jiǎn)單說(shuō)明了ListView的實(shí)現(xiàn),需要的朋友可以參考下2014-08-08解析Android截取手機(jī)屏幕兩種實(shí)現(xiàn)方案
這篇文章主要介紹了解析Android截取手機(jī)屏幕兩種實(shí)現(xiàn)方案,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04Android調(diào)試華為和魅族手機(jī)logcat不顯示的問(wèn)題
今天小編就為大家分享一篇關(guān)于Android調(diào)試華為和魅族手機(jī)logcat不顯示的問(wèn)題,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10Android實(shí)現(xiàn)調(diào)用攝像頭和相冊(cè)的方法
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)調(diào)用攝像頭和相冊(cè)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04Android加載loading對(duì)話(huà)框的功能及實(shí)例代碼(不退出沉浸式效果)
這篇文章主要介紹了Android加載loading對(duì)話(huà)框的功能及實(shí)例代碼,不退出沉浸式效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-12-12