android 每個塊半徑不同的扇形圖,自定義view

来源:https://www.cnblogs.com/wangxinqiang1995/archive/2018/07/19/9334511.html
-Advertisement-
Play Games

1.首先看效果圖 2.自定義PieChartView,繼承自View,下邊為PieChartView代碼 之後,在activity中,只需找到組件,傳入數據,調用 invalidate() 進行重繪即可。 ...


1.首先看效果圖

2.自定義PieChartView,繼承自View,下邊為PieChartView代碼

package com.yingjinbao.im.peach.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
* Created by wanger on 07/19/2018.
*/

public class PieChartView extends View {

private int mHeight, mWidth;//寬高
private Paint mPaint;//扇形的畫筆
private Paint mTextPaint;//畫文字的畫筆

private int centerX, centerY;//中心坐標

private int maxNum = 4;//扇形圖的最大塊數,超出部分自動合併到最後一塊上去

double total;//數據的總和
double[] datas;//數據集
String[] texts;//每個數據對應的文字集

//顏色 預設的顏色
private int[] mColors = {
Color.parseColor("#FFC65B"), Color.parseColor("#FD5998"),
Color.parseColor("#8971FB"), Color.parseColor("#676974")
};

private int mTextSize;//文字大小

private int radius = 1000;//半徑

public PieChartView(Context context) {
super(context);
}

public PieChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

//初始化
private void init() {
mTextSize = 25;

mPaint = new Paint();
//當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的圖形樣式, 如圓形樣Cap.ROUND,或方形樣式Cap.SQUARE
mPaint.setStrokeCap(Paint.Cap.ROUND);
//設置是否使用抗鋸齒功能,會消耗較大資源,繪製圖形速度會變慢。
mPaint.setAntiAlias(true);

mTextPaint = new Paint();
//設置繪製文字的字型大小大小
mTextPaint.setTextSize(mTextSize);
//當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的粗細度
mTextPaint.setStrokeWidth(3);
//設置是否使用抗鋸齒功能,會消耗較大資源,繪製圖形速度會變慢。
mTextPaint.setAntiAlias(true);
//設置繪製的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。
mTextPaint.setColor(Color.WHITE);
}


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲取寬高 不要設置wrap_content
mHeight = MeasureSpec.getSize(heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//無數據
if (datas == null || datas.length == 0) return;

centerX = (getRight() - getLeft()) / 2;
centerY = (getBottom() - getTop()) / 2;
int min = mHeight > mWidth ? mWidth : mHeight;
if (radius > min / 2) {
radius = (int) ((min - getPaddingTop() - getPaddingBottom()) / 3.5);
}

//畫扇形
canvas.save();
drawCircle(canvas);
canvas.restore();


//線與文字
canvas.save();
drawLineAndText(canvas);
canvas.restore();

}


//畫線與文字
private void drawLineAndText(Canvas canvas) {
int start = 0;
canvas.translate(centerX, centerY);//平移畫布到中心
mPaint.setStrokeWidth(4);
for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) {

if (i == (maxNum < datas.length ? maxNum : datas.length) - 1){
drawLine(canvas, start, 360 - start, texts[i], mColors[i % mColors.length],i);
}else {
float angles = (float) ((datas[i] * 1.0f / total) * 360);
drawLine(canvas, start, angles, texts[i], mColors[i % mColors.length],i);
start += angles;
}
}
}

private void drawLine(Canvas canvas, int start, float angles, String text, int color,int position) {
mPaint.setColor(color);
//mTextPaint.setColor(color);
float stopX, stopY;
stopX = (float) ((radius + 40) * Math.cos((2 * start + angles) / 2 * Math.PI / 180));
stopY = (float) ((radius + 40) * Math.sin((2 * start + angles) / 2 * Math.PI / 180));

switch (position){
case 0:
canvas.drawLine((float) ((radius * 0.5) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.5) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 1:
canvas.drawLine((float) ((radius * 0.7) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.7) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 2:
canvas.drawLine((float) ((radius * 1.1) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 1.1) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 3:
canvas.drawLine((float) ((radius * 0.9) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.9) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
default:
canvas.drawLine((float) (radius * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) (radius * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
}
//canvas.drawLine(0, 0, stopX, stopY, mPaint);
//畫橫線
int dx;//判斷橫線是畫在左邊還是右邊
int endX;
if (stopX > 0) {
endX = (int) (stopX + 110);
} else {
endX = (int) (stopX - 110);
}
//畫橫線
canvas.drawLine(stopX, stopY,
endX, stopY, mPaint
);
dx = (int) (endX - stopX);

//測量文字大小
Rect rect = new Rect();
mTextPaint.getTextBounds(text, 0, text.length(), rect);
int w = rect.width();
int h = rect.height();
int offset = 20;//文字在橫線的偏移量
//畫文字
canvas.drawText(text, 0, text.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY - 5, mTextPaint);

//測量百分比大小
String percentage = (datas[position] / total) * 100 + "";
percentage = percentage.substring(0, percentage.length() > 4 ? 4 : percentage.length()) + "%";
mTextPaint.getTextBounds(percentage, 0, percentage.length(), rect);
w = rect.width() - 10;
//畫百分比
canvas.drawText(percentage, 0, percentage.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY + h, mTextPaint);

}

//畫扇形
private void drawCircle(Canvas canvas) {
RectF rect = null;
int start = 0;
for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) {
if (i == 0){
rect = new RectF((float) (centerX - radius * 0.5), (float) (centerY - radius * 0.5),
(float) (centerX + radius * 0.5), (float) (centerY + radius * 0.5));
}else if (i == 1){
rect = new RectF((float) (centerX - radius * 0.7), (float) (centerY - radius * 0.7),
(float) (centerX + radius * 0.7), (float) (centerY + radius * 0.7));
}else if (i == 2){
rect = new RectF((float) (centerX - radius * 1.1), (float) (centerY - radius * 1.1),
(float) (centerX + radius * 1.1), (float) (centerY + radius * 1.1));
}else if (i == 3){
rect = new RectF((float) (centerX - radius * 0.9), (float) (centerY - radius * 0.9),
(float) (centerX + radius * 0.9), (float) (centerY + radius * 0.9));
}else {
rect = new RectF((float) (centerX - radius * 1), (float) (centerY - radius * 1),
(float) (centerX + radius * 1), (float) (centerY + radius * 1));
}

if (i == (maxNum < datas.length ? maxNum : datas.length) - 1){
float angles = 360 - start;
mPaint.setColor(mColors[i % mColors.length]);

if (i == 2){
canvas.drawArc(rect, start, angles, true, mPaint);

mPaint.setColor(Color.parseColor("#34374A"));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(8);
rect = new RectF((float) (centerX - radius * 1.03), (float) (centerY - radius * 1.03),
(float) (centerX + radius * 1.03), (float) (centerY + radius * 1.03));

canvas.drawArc(rect, start, angles, false, mPaint);
init();
}else {
canvas.drawArc(rect, start, angles, true, mPaint);
}

start += angles;
}else {
float angles = (float) ((datas[i] * 1.0f / total) * 360);
mPaint.setColor(mColors[i % mColors.length]);

if (i == 2){
canvas.drawArc(rect, start, angles, true, mPaint);

mPaint.setColor(Color.parseColor("#34374A"));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(8);
rect = new RectF((float) (centerX - radius * 1.03), (float) (centerY - radius * 1.03),
(float) (centerX + radius * 1.03), (float) (centerY + radius * 1.03));

canvas.drawArc(rect, start, angles, false, mPaint);
init();
}else {
canvas.drawArc(rect, start, angles, true, mPaint);
}


start += angles;
}
}
}

//setter
public void setColors(int[] mColors) {
this.mColors = mColors;
invalidate();
}

public void setTextSize(int mTextSize) {
this.mTextSize = mTextSize;
mTextPaint.setTextSize(mTextSize);
invalidate();
}

public void setRadius(int radius) {
this.radius = radius;
invalidate();
}

public void setMaxNum(int maxNum) {
this.maxNum = maxNum;
invalidate();
}

public void setDatas(double[] datas) {
this.datas = datas;
total = 0;
for (int i = 0;i < datas.length;i++){
total += datas[i];
}
}

public void setTexts(String[] texts) {
this.texts = texts;
}

}
3.使用,首先在XML文件中調用

 之後,在activity中,只需找到組件,傳入數據,調用 invalidate() 進行重繪即可。

 


 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.WITH ROLLUP:在分組的基礎上進行統計數據。 例子:首先在name欄位上進行分組,然後在分組的基礎上進行統計 參數說明:如果a==null,則選擇b;如果b==null,則選擇c;如果a!=null,則選擇a;如果a b c 都為null ,則返回為null(沒意義)。 以下實例中如果名 ...
  • 觸發器,DML觸發器(DELETE觸發器,INSERT觸發器,UPDATE觸發器,INSTEAD OF觸發器),DDL觸發器,嵌套觸發器,遞歸觸發器,啟用禁用觸發器,資料庫級別觸發器,伺服器級別觸發器 ...
  • 多表from子句後面 ...
  • 一. 本章介紹mysql中的索引的分類,存儲,使用方法的介紹 1. 索引的存儲分類 MyISAM存儲引擎的表的數據和索引是自動分開存儲的,各自是獨立的一個文件, innodb 存儲引擎的表的數據和索引是存儲在同一個表空間裡面,可以有多個文件組成。 MyISAM和Innodb存儲引擎都支持btree索 ...
  • 最近看友盟的SDK更新日誌:(設備系統的正常升級不會改變OpenUDID) Apple公司於2013年5月1日開始,拒絕採集UDID的App上架App Store。 為適應Apple公司的這一政策,2013年4月23日之後,友盟統計分析iOS平臺的SDK只提供OpenUDID版本。 OpenUDID ...
  • 前言 ​ 本文是基於《第一行代碼》整理成的筆記,mark下自己的學習路程。 ​ 本章將通過實驗著重介紹ACtivity。 項目結構 ​ 首先我們創建一個安卓項目,來認識一下項目結構; 四大組件之首——Activity Activity 就是我們所看到的界面,新建一個類,繼承Activity,重寫on ...
  • 1.將字體加入到項目中 2.在info.plist文件中加入相應信息,這一步實際上實在項目的Info頁裡面增加Fonts provided by application項,並設置相應的ttf文件進去,這樣就告訴了應用,我要加入新的字體了,對應的字體文件是哪些。 3.字型檔文件應該是準備好了,下麵我們需 ...
  • iOS 判斷數字 - (BOOL) deptNumInputShouldNumber:(NSString *)str { if (str.length == 0) { return NO; } NSString *regex = @"[0-9]*"; NSPredicate *pred = [NSP ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...