亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

利用kotlin實現一個餅圖實例代碼

2024-07-21 23:03:41
字體:
來源:轉載
供稿:網友

前言

餅圖是許多人最熟悉的圖表類型,也是使用頻率最高的圖表類型之一,本文主要給大家介紹了關于利用kotlin實現餅圖的相關內容,分享出來供大家參考學習,代碼不難,所以打算用kotlin來實現,增加熟練度,下面來一起看看吧。

先看看做的是什么

kotlin,圖形界面,實現

看完圖,我們來整理下思路

  • 餅圖居中,每塊區域都是一個扇形,需要canvas.drawArc根據角度來繪制
  • 需要path.arcTo定位到扇形弧度的一半來繪制折線的起點
  • 通過canvas.drawPath繪制折線,折線的長度根據餅圖大小來設置比例
  • 通過canvas.drawText繪制文字,文字的大小根據餅圖的大小來設置比例,繪制文字的位置需要計算文字的寬度

思路清晰后就擼起袖子加油干

知識點

我們先來了解一個概念,我們在paint畫扇形的時候,對應的度數是在哪個位置呢?

kotlin,圖形界面,實現

看到圖后應該明白了吧

繪制餅圖

我們先來看看他的參數,很明顯,左、上、右、下參數形成一個面板,startAngle 為起始的角度,sweepAngle 為從起始角度開始繪制多少度,useCenter為是否連接到圓心,paint為畫筆

 public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) { super.drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint); }

我們以當前控件的width、height為面板來畫一個圓形的餅圖

 @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.drawArc(0f, 0f, width, height, 0f, 360f, true, paintRed) }

哇塞,好丑哦,結果顯示的是一個橢圓,如果要繪制一個圓形的餅圖,我們必須得保證left=top=right=bottom

kotlin,圖形界面,實現

設置餅圖居中

 /** * view的寬度 */ var width: Float = 0f /** * view的高度 */ var height: Float = 0f /** * drawArc距離左邊的距離 */ var left: Float = 0f /** * drawArc距離上邊的距離 */ var top: Float = 0f /** * drawArc距離右邊的距離 */ var right: Float = 0f /** * drawArc距離下邊的距離 */ var bottom: Float = 0f @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.drawArc(left, top, right, bottom, 0f, 360f, true, paint) }  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) setBackgroundColor(resources.getColor(R.color.black)) width = w.toFloat() height = h.toFloat() left = width / 4f top = width / 4f right = width - left bottom = width - top  }

完美居中

kotlin,圖形界面,實現

接下來,我們要把上面從0度到360度多分幾個步驟來繪制

 @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun onDraw(canvas: Canvas) { super.onDraw(canvas) ... canvas.drawArc(left, top, right, bottom, 0f, 20f, true, paintPuple) canvas.drawArc(left, top, right, bottom, 20f, 10f, true, paintGray) canvas.drawArc(left, top, right, bottom, 30f, 40f, true, paintGreen) canvas.drawArc(left, top, right, bottom, 70f, 110f, true, paintBlue) canvas.drawArc(left, top, right, bottom, 180f, 110f, true, paintRed) canvas.drawArc(left, top, right, bottom, 290f, 70f, true, paintYellow) }

還不錯

上圖的度數是寫死的,現在我們來把他寫活

提供一個設置個數的集合,比如農名伯伯賣水果,梨子賣了10個,香蕉賣了3個,蘋果賣了7個,那么這個個數的集合為pieList=(10,3,7)。

因為餅圖是根據角度來繪制的,我們必須將這個個數集合換算成角度集合,換算的過程中我們需要知道每一種水果所占總水果的比例,然后通過這個比例去乘上360度,就知道每一種水果所占的度數。

梨子的占比為10/(10+3+7)=1/2,可得梨子占餅圖的度數為1/2*360=180度,按照這種方式計算,香蕉和蘋果占餅圖的度數分別為54度和126度,那么,餅圖的分布也就出來了

現在,我們來定義一個個數集合,計算出比例的集合和度數的集合,下面是比例的集合,度數的集合我們在繪制的時候再去計算

 /** * 個人分類集合 */ var pieList = arrayListOf(10f,3f,7f) /** * 餅圖所占的比例 */ var scaleList = arrayListOf<Float>() /** * 個數分類的總量 */ var total: Float = 0f  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) //計算個數的總和 total = pieList.sum() //存儲比例值 for (a in pieList) {  scaleList.add(a.div(total)) } }

比例集合拿到了,接下來,我們去循環這個比例值,然后將比例值乘上360度,計算出角度值,供drawArc的sweepAngle使用,但是,我們還缺少一個startAngle起始角度,我們可以定義一個起始角度為0度,然后每次根據計算出的角度值sweepAngle去累加起始度數,用代碼來實現下

 /** * 記錄當前畫餅圖的度數 */ var currentDegree: Float = 0f /** * 累加餅圖的度數作為下一個繪制的起始度數 */ var srctorDegree: Float = 0f  @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun onDraw(canvas: Canvas) { super.onDraw(canvas)  for (scale in scaleList) {  val paint = Paint()  paint.strokeWidth = dip(10.0f).toFloat()  paint.isAntiAlias = true  //定義一個隨機生成的顏色數,來區分不同的扇形區域  val hex = "#" + Integer.toHexString((-16777216 * Math.random()).toInt())  paint.color = Color.parseColor(hex)  //角度數  srctorDegree = scale * 360  canvas.drawArc(left, top, right, bottom, currentDegree, srctorDegree, true, paint)  //累加角度  currentDegree += srctorDegree } }

ok,現在我們可以隨機的去定義個數來生成占比的餅圖了

kotlin,圖形界面,實現

繪制折線

接下來,我們來繪制折線,折線的起點是每個扇形弧上的一半,path的arcTo方法也可以繪制圓,且方法參數使用也是一樣,我們可以讓arcTo跟著canvas.drawArc一塊畫,arcTo的startAngle起始角度為canvas.drawArc起始角度加上sweepAngle度數的一半,這樣,就定位到了弧邊的一半,arcTo的sweepAngle為0就行了,我們只定位,不繪制

  ...  canvas.drawArc(left, top, right, bottom, currentDegree, srctorDegree, true, paint)  val path = Path()  path.arcTo(left, top, right, bottom, currentDegree + srctorDegree / 2, 0f, false)  ...

現在,path的位置定位到弧邊的一半了,接下來,我們要知道當前path的坐標然后根據坐標去繪制折線,

  val bounds = RectF()  //將path當前的坐標賦值給bounds  path.computeBounds(bounds, true)

現在拿到坐標了,我們再來看看效果圖,折線和文字呈四個方向,我們不如把餅圖分成四個區域,以圓心為坐標軸原點,切分四個象限:

  • 第一象限:折線為右上,文字在折線右邊
  • 第二象限:折線為左上,文字在折線左邊
  • 第三象限:折線為左下,文字在折線左邊
  • 第四象限:折線為右下,文字在折線右邊

那么,接下來就是如何判斷當前起始點在哪個象限了,先以第一象限為例,如果當前的坐標大于餅圖橫軸方向一半,并且小于餅圖縱軸方向的一半,那么就是第一象限,其他依次類推

 /** * 橫線的長度 */ var lineae: Int = 30 /** * 斜線的長度 */ var slantLine: Int = 30  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh)  //計算橫線的比例  lineae = (width / 30f).toInt()  //計算斜線的比例  slantLine = (width / 40f).toInt() }  @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun onDraw(canvas: Canvas) { super.onDraw(canvas) for (scale in scaleList) {  ...  val path = Path()  path.arcTo(left, top, right, bottom, currentDegree + srctorDegree / 2, 0f, false)  val bounds = RectF()  path.computeBounds(bounds, true)   //第一象限  if (bounds.left >= width / 2 && bounds.top <= width / 2) {  path.lineTo(bounds.left + lineae, bounds.top)  path.lineTo(bounds.left + lineae + slantLine, bounds.top - slantLine)  canvas.drawPath(path, paintLine)  //第二象限  } else if (bounds.left <= width / 2 && bounds.top <= width / 2) {  path.lineTo(bounds.left - lineae, bounds.top)  path.lineTo(bounds.left - lineae - slantLine, bounds.top - slantLine)  canvas.drawPath(path, paintLine)  //第三象限  } else if (bounds.left <= width / 2 && bounds.top >= width / 2) {  path.lineTo(bounds.left - lineae, bounds.top)  path.lineTo(bounds.left - lineae - slantLine, bounds.top + slantLine)  canvas.drawPath(path, paintLine)  //第四象限  } else {  path.lineTo(bounds.left + lineae, bounds.top)  path.lineTo(bounds.left + lineae + slantLine, bounds.top + slantLine)  canvas.drawPath(path, paintLine)  }   }  ... } 

kotlin,圖形界面,實現   

哎呀,出來了

繪制文字

接下來就是繪制文字了,第一、四象限還好,文字可以在折線后面跟著畫,但是二、三象限的文字就不允許了,我們必須往前移動文字寬度的距離才能完美銜接到折線上,所以,我們來定義一個計算文字的方法

 /** * 獲取文字的寬度 */ private fun getStringWidth(str: String): Float = paintLine.measureText(str)

文字是會隨著餅圖的大小進行改變的,所以設置文字大小的比例

 paintLine.textSize = dip(width / 100).toFloat()

接下來就開始繪制文字吧

 @RequiresApi(Build.VERSION_CODES.LOLLIPOP) override fun onDraw(canvas: Canvas) { super.onDraw(canvas)  ...   //獲取當前的百分比文字  val textStr = String.format("%.2f%%", scale * 100)  //獲取文字的寬度  val textWidth = getStringWidth(textStr)     //第一象限  if (bounds.left >= width / 2 && bounds.top <= width / 2) {  ...  canvas.drawText(textStr, bounds.left + lineae + slantLine, bounds.top - slantLine, paintText)  ...  //第二象限  } else if (bounds.left <= width / 2 && bounds.top <= width / 2) {  ...  canvas.drawText(textStr, bounds.left - lineae - slantLine - textWidth, bounds.top - slantLine, paintText)  ...  //第三象限  } else if (bounds.left <= width / 2 && bounds.top >= width / 2) {  ...  canvas.drawText(textStr, bounds.left - lineae - slantLine - textWidth, bounds.top + lineae, paintText)  ...  //第四象限  } else {  ...  canvas.drawText(textStr, bounds.left + lineae + slantLine, bounds.top + slantLine, paintText)  ...  }   }

嗯,還不錯,

kotlin,圖形界面,實現

然后我們再看看效果圖,餅圖中間還有一塊與背景色一樣的黑圓,這不跟簡單了嘛

 //定義中間黑圓的畫筆 paintCicle.color = resources.getColor(R.color.black) paintCicle.isAntiAlias = true paintCicle.style = Paint.Style.FILL   @RequiresApi(Build.VERSION_CODES.LOLLIPOP)  override fun onDraw(canvas: Canvas) {  super.onDraw(canvas)    ...    //在循環結束餅圖的時候,以餅圖的原點為中心畫圓   canvas.drawCircle(width / 2, width / 2, width / 8, paintCicle)  }

kotlin,圖形界面,實現

然后我們暴露一個方法,提供給Activity去調用

 /**  * 設置扇形參數  */ fun setPieData(a: ArrayList<Float>) {  pieList.clear()  pieList.addAll(a)  invalidate() }

那么,Activity就可以這么去調用了

 override fun onCreate(savedInstanceState: Bundle?) {  super.onCreate(savedInstanceState)  setContentView(R.layout.activity_second)  pie1.setPieData(arrayListOf(1f,10f,15f,9f,15f))  pie2.setPieData(arrayListOf(3f,8f,15f,7f,9f))  pie3.setPieData(arrayListOf(9f,3f,7f,3f,4f,2f,1f)) }

kotlin,圖形界面,實現

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国模精品视频一区二区| 91久久久久久国产精品| 国产精自产拍久久久久久| 欧美精品一区二区三区国产精品| 精品成人在线视频| 亚洲欧美日韩在线一区| 亚洲日本aⅴ片在线观看香蕉| 亚洲日本中文字幕免费在线不卡| 日韩国产欧美精品一区二区三区| 91老司机精品视频| 午夜精品一区二区三区av| 亚洲欧洲黄色网| 日本道色综合久久影院| 91wwwcom在线观看| 一区二区三区视频免费| 成人性生交大片免费观看嘿嘿视频| 97色在线观看免费视频| 久久深夜福利免费观看| 欧美亚洲日本网站| 一区二区成人精品| 91青草视频久久| 欧美激情一区二区三级高清视频| 国产精品女人久久久久久| 国产精品高潮视频| 久久精品免费电影| 日韩视频免费在线观看| 亚洲天堂一区二区三区| 国产亚洲精品久久久久动| 亚洲精品xxx| 久久久久一本一区二区青青蜜月| zzjj国产精品一区二区| 日韩精品中文字幕在线| 亚洲美女激情视频| 欧美性猛交xxxx黑人| 久久久免费电影| 日韩av在线免费观看一区| 成人97在线观看视频| 欧美激情精品久久久久久久变态| 欧美做爰性生交视频| 欧美亚洲激情视频| 亚洲淫片在线视频| 亚洲精品aⅴ中文字幕乱码| 精品成人国产在线观看男人呻吟| 亚洲最大福利视频网| 国产精品91在线观看| 久久久久成人网| 久久久久久久久久久久久久久久久久av| 亚洲高清av在线| 成人福利网站在线观看| 欧美在线日韩在线| 亚洲日韩欧美视频一区| 九九热99久久久国产盗摄| 久久亚洲精品一区二区| 国产网站欧美日韩免费精品在线观看| 亚洲人成人99网站| 日韩精品久久久久| 狠狠躁夜夜躁人人躁婷婷91| 久久香蕉频线观| 久久久久九九九九| 亚洲精品福利在线观看| 国产精品一区二区在线| 亚洲欧美日韩中文在线制服| 奇米4444一区二区三区| 国产精品偷伦一区二区| …久久精品99久久香蕉国产| 精品久久久久久久大神国产| 国产成人免费av电影| 色偷偷88888欧美精品久久久| 国产精品1区2区在线观看| 亚洲石原莉奈一区二区在线观看| 日韩欧美在线观看| 久久99国产精品自在自在app| 91av在线播放视频| 欧美一乱一性一交一视频| 中文字幕在线观看亚洲| 中文字幕在线亚洲| 亚洲精品国精品久久99热| 欧美性xxxxhd| 久久久av亚洲男天堂| 国产精品久久久久久久久| 色哟哟网站入口亚洲精品| 成人激情视频在线| 欧美日韩精品在线播放| 91av在线播放视频| 欧美精品在线观看| 国内精品久久久久伊人av| 成人网在线观看| 亚洲欧美在线播放| 亚洲欧美国产日韩中文字幕| 26uuu亚洲伊人春色| 一区三区二区视频| 91社区国产高清| 欧美色xxxx| 欧美成人国产va精品日本一级| 国产精品亚洲视频在线观看| 91夜夜揉人人捏人人添红杏| 亚洲精品在线看| 欧美性感美女h网站在线观看免费| 成人免费视频xnxx.com| 色偷偷888欧美精品久久久| 久久免费视频观看| 日韩高清中文字幕| 欧美高清视频在线观看| 91精品国产综合久久男男| 亚洲精品美女在线观看播放| 一区二区三区视频观看| 亚洲摸下面视频| 国产在线观看91精品一区| 欧美丰满少妇xxxxx做受| 日韩有码片在线观看| 国产精品白嫩初高中害羞小美女| 亚洲欧美成人精品| 久久久999精品视频| 啪一啪鲁一鲁2019在线视频| 国产视频久久久| 欧美日韩精品中文字幕| 91热福利电影| 国产美女直播视频一区| 色综久久综合桃花网| 久久精品99久久久久久久久| 欧美黄色片在线观看| 日韩电影中文字幕在线| 亚洲欧美综合区自拍另类| 精品毛片网大全| 久久久久久美女| 欧美高跟鞋交xxxxxhd| 成人在线视频网| 国产精品视频男人的天堂| 国产精品露脸av在线| 曰本色欧美视频在线| 久久香蕉国产线看观看网| 亚洲国产婷婷香蕉久久久久久| 另类少妇人与禽zozz0性伦| 国产精品视频久久| 91精品国产综合久久久久久久久| 欧美国产日韩视频| 懂色av中文一区二区三区天美| 欧美日韩另类视频| xxav国产精品美女主播| 深夜成人在线观看| 一区二区三区视频免费| 九九精品视频在线观看| 久久精品91久久久久久再现| 中国china体内裑精亚洲片| 欧美裸体男粗大视频在线观看| 日韩欧美中文在线| 正在播放欧美视频| 色婷婷**av毛片一区| 亚洲国产成人91精品| 亚洲毛片一区二区| 精品中文字幕在线观看| 亚洲国产精品人人爽夜夜爽| 国产一区二区三区网站| 国产色视频一区| 91色视频在线导航| 国产视频精品久久久| 隔壁老王国产在线精品| 久久久久五月天| 亚洲女人天堂av| 久久综合伊人77777尤物| 国产成人av网址| 久久久伊人日本| 国产视频精品xxxx| 久久亚洲精品一区二区|