iOS 解決Charts框架PieChartView標(biāo)簽重疊問題

背景

項(xiàng)目做完出來的時候讼载,我就發(fā)現(xiàn)了PieChartView標(biāo)簽重疊問題作儿,奈何在網(wǎng)上沒找解決辦法像街,而Android對應(yīng)的MPAndroidChart有相應(yīng)的解決辦法筹裕,于是照搬到iOS下较鼓。

思路

分析源碼我們知道圖表的繪制過程是由PieChartRenderer類控制的椎木,所以我們需要自定義PieChartRenderer類,而PieChartRenderer是在PieChartView中引用的博烂,于是我們也需要自定義PieChartView類:

代碼

自定義HDPieChartRenderer

//
//? HDPieChartRenderer.swift
//
//? Created by Simon.Hua on 2021/11/16.
//

import UIKit
import Charts
import Foundation
import CoreGraphics

open class HDPieChartRenderer: PieChartRenderer{
??? init(withChart chart:PieChartView, animator:Animator, viewPortHandler:ViewPortHandler){
??????? super.init(chart: chart, animator: animator, viewPortHandler: viewPortHandler)
??? }
?? ?
??? private func minData(_ recordY:Array<Array<CGFloat>>, pt1y:CGFloat) ->Array<CGFloat>{
??????? var bigD:Array<CGFloat> = Array<CGFloat>()
??????? var nearestlist:Array<CGFloat> = Array<CGFloat>()
??????? var nearestlistCopy:Array<CGFloat> = Array<CGFloat>()
??????? for k in 0..<recordY[0].count {
??????????? if recordY[0][k] != 0 {
??????????????? bigD.append(abs(recordY[0][k] - pt1y))
??????????????? nearestlist.append(recordY[0][k])
??????????????? nearestlistCopy.append(recordY[1][k])
??????????? }
??????? }
?????? ?
??????? //距離最近的點(diǎn)香椎,數(shù)值
??????? var rF:Array = [CGFloat](repeating: 0, count: 2)
??????? if bigD.count == 0 {
??????????? return rF
??????? }
?????? ?
??????? var minD = bigD[0]
??????? rF[0] = nearestlist[0]
??????? rF[1] = nearestlistCopy[0]
?????? ?
??????? for g in 0..<bigD.count {
??????????? if bigD[g] < minD {
??????????????? minD = bigD[g]
??????????????? rF[0] = nearestlist[g]
??????????????? rF[1] = nearestlistCopy[g]
??????????? }
??????? }
?????? ?
??????? return rF
??? }
?? ?
??? open override func drawValues(context: CGContext)
??? {
??????? guard
??????????? let chart = chart,
??????????? let data = chart.data
??????????? else { return }

??????? let center = chart.centerCircleBox

??????? // get whole the radius
??????? let radius = chart.radius
??????? let rotationAngle = chart.rotationAngle
??????? let drawAngles = chart.drawAngles
??????? let absoluteAngles = chart.absoluteAngles

??????? let phaseX = animator.phaseX
??????? let phaseY = animator.phaseY

??????? var labelRadiusOffset = radius / 10.0 * 3.0

??????? if chart.drawHoleEnabled
??????? {
??????????? labelRadiusOffset = (radius - (radius * chart.holeRadiusPercent)) / 2.0
??????? }

??????? let labelRadius = radius - labelRadiusOffset

??????? let dataSets = data.dataSets

??????? let yValueSum = (data as! PieChartData).yValueSum

??????? let drawEntryLabels = chart.isDrawEntryLabelsEnabled
??????? let usePercentValuesEnabled = chart.usePercentValuesEnabled

??????? var angle: CGFloat = 0.0
??????? var xIndex = 0

??????? context.saveGState()
??????? defer { context.restoreGState() }

??????? for i in 0 ..< dataSets.count
??????? {
??????????? guard let dataSet = dataSets[i] as? IPieChartDataSet else { continue }

??????????? let drawValues = dataSet.isDrawValuesEnabled

??????????? if !drawValues && !drawEntryLabels && !dataSet.isDrawIconsEnabled
??????????? {
??????????????? continue
??????????? }

??????????? let iconsOffset = dataSet.iconsOffset

??????????? let xValuePosition = dataSet.xValuePosition
??????????? let yValuePosition = dataSet.yValuePosition

??????????? let valueFont = dataSet.valueFont
??????????? let entryLabelFont = dataSet.entryLabelFont ?? chart.entryLabelFont
??????????? let lineHeight = valueFont.lineHeight
??????????? let textHeight = entryLabelFont?.lineHeight

??????????? guard let formatter = dataSet.valueFormatter else { continue }
?????????? ?
??????????? var leftRecordY = [[CGFloat]](repeating: [CGFloat](repeating: 0, count: dataSet.entryCount), count: 2)
??????????? var rightRecordY = [[CGFloat]](repeating: [CGFloat](repeating: 0, count: dataSet.entryCount), count: 2)

??????????? for j in 0 ..< dataSet.entryCount
??????????? {
??????????????? guard let e = dataSet.entryForIndex(j) else { continue }
??????????????? let pe = e as? PieChartDataEntry

??????????????? if xIndex == 0
??????????????? {
??????????????????? angle = 0.0
??????????????? }
??????????????? else
??????????????? {
??????????????????? angle = absoluteAngles[xIndex - 1] * CGFloat(phaseX)
??????????????? }

??????????????? let sliceAngle = drawAngles[xIndex]
??????????????? let sliceSpace = getSliceSpace(dataSet: dataSet)
??????????????? let sliceSpaceMiddleAngle = sliceSpace / (labelRadius * .pi / 180)

??????????????? // offset needed to center the drawn text in the slice
??????????????? let angleOffset = (sliceAngle - sliceSpaceMiddleAngle / 2.0) / 2.0

??????????????? angle = angle + angleOffset

??????????????? let transformedAngle = rotationAngle + angle * CGFloat(phaseY)

??????????????? let value = usePercentValuesEnabled ? e.y / yValueSum * 100.0 : e.y
??????????????? let valueText = formatter.stringForValue(
??????????????????? value,
??????????????????? entry: e,
??????????????????? dataSetIndex: i,
??????????????????? viewPortHandler: viewPortHandler)

??????????????? let sliceXBase = cos(transformedAngle * .pi / 180)
??????????????? let sliceYBase = sin(transformedAngle * .pi / 180)

??????????????? let drawXOutside = drawEntryLabels && xValuePosition == .outsideSlice
??????????????? let drawYOutside = drawValues && yValuePosition == .outsideSlice
??????????????? let drawXInside = drawEntryLabels && xValuePosition == .insideSlice
??????????????? let drawYInside = drawValues && yValuePosition == .insideSlice

??????????????? let valueTextColor = dataSet.valueTextColorAt(j)
??????????????? let entryLabelColor = dataSet.entryLabelColor ?? chart.entryLabelColor

??????????????? if drawXOutside || drawYOutside
??????????????? {
??????????????????? let valueLineLength1 = dataSet.valueLinePart1Length
??????????????????? let valueLineLength2 = dataSet.valueLinePart2Length
??????????????????? let valueLinePart1OffsetPercentage = dataSet.valueLinePart1OffsetPercentage

??????????????????? var pt2: CGPoint
??????????????????? var labelPoint: CGPoint
??????????????????? var align: NSTextAlignment

??????????????????? var line1Radius: CGFloat

??????????????????? if chart.drawHoleEnabled
??????????????????? {
??????????????????????? line1Radius = (radius - (radius * chart.holeRadiusPercent)) * valueLinePart1OffsetPercentage + (radius * chart.holeRadiusPercent)
??????????????????? }
??????????????????? else
??????????????????? {
??????????????????????? line1Radius = radius * valueLinePart1OffsetPercentage
??????????????????? }

??????????????????? let polyline2Length = dataSet.valueLineVariableLength
??????????????????????? ? labelRadius * valueLineLength2 * abs(sin(transformedAngle * .pi / 180))
??????????????????????? : labelRadius * valueLineLength2

??????????????????? let pt0 = CGPoint(
??????????????????????? x: line1Radius * sliceXBase + center.x,
??????????????????????? y: line1Radius * sliceYBase + center.y)

??????????????????? var pt1 = CGPoint(
??????????????????????? x: labelRadius * (1 + valueLineLength1) * sliceXBase + center.x,
??????????????????????? y: labelRadius * (1 + valueLineLength1) * sliceYBase + center.y)

??????????????????? if transformedAngle.truncatingRemainder(dividingBy: 360.0) >= 90.0 && transformedAngle.truncatingRemainder(dividingBy: 360.0) <= 270.0
??????????????????? {
??????????????????????? let nearestPoint = minData(leftRecordY, pt1y: pt1.y)
??????????????????????? leftRecordY[0][j] = pt1.y
??????????????????????? //判斷是否需要挪位置
??????????????????????? if (nearestPoint[0] != 0) && (abs(nearestPoint[0] - pt1.y) < (textHeight! + lineHeight)) {
??????????????????????????? pt1 = CGPoint(x: pt1.x, y: nearestPoint[1] - textHeight!)
??????????????????????? }
?
??????????????????????? pt2 = CGPoint(x: pt1.x - polyline2Length, y: pt1.y)
??????????????????????? align = .right
??????????????????????? labelPoint = CGPoint(x: pt2.x - 5, y: pt2.y - textHeight!)
??????????????????????? leftRecordY[1][j] = pt1.y
??????????????????? }
??????????????????? else
??????????????????? {
??????????????????????? let nearestPoint = minData(rightRecordY, pt1y: pt1.y)
??????????????????????? rightRecordY[0][j] = pt1.y
?????????????????????? ?
??????????????????????? //判斷是否需要挪位置
??????????????????????? if (nearestPoint[0] != 0) && (abs(nearestPoint[0] - pt1.y) < (textHeight! + lineHeight)){
??????????????????????????? pt1 = CGPoint(x: pt1.x, y: nearestPoint[1] + textHeight!)
??????????????????????? }
?????????????????? ?
??????????????????????? pt2 = CGPoint(x: pt1.x + polyline2Length, y: pt1.y)
??????????????????????? align = .left
??????????????????????? labelPoint = CGPoint(x: pt2.x + 5, y: pt2.y - textHeight!)
??????????????????????? rightRecordY[1][j] = pt1.y
??????????????????? }

??????????????????? DrawLine: do
??????????????????? {
??????????????????????? if dataSet.useValueColorForLine
??????????????????????? {
??????????????????????????? context.setStrokeColor(dataSet.color(atIndex: j).cgColor)
??????????????????????? }
??????????????????????? else if let valueLineColor = dataSet.valueLineColor
??????????????????????? {
??????????????????????????? context.setStrokeColor(valueLineColor.cgColor)
??????????????????????? }
??????????????????????? else
??????????????????????? {
??????????????????????????? return
??????????????????????? }
??????????????????????? context.setLineWidth(dataSet.valueLineWidth)

??????????????????????? context.move(to: CGPoint(x: pt0.x, y: pt0.y))
??????????????????????? context.addLine(to: CGPoint(x: pt1.x, y: pt1.y))
??????????????????????? context.addLine(to: CGPoint(x: pt2.x, y: pt2.y))

??????????????????????? context.drawPath(using: CGPathDrawingMode.stroke)
??????????????????? }
?????????????????? ?
??????????????????? if drawXOutside && drawYOutside
??????????????????? {
??????????????????????? ChartUtils.drawText(
??????????????????????????? context: context,
??????????????????????????? text: valueText,
??????????????????????????? point: labelPoint,
??????????????????????????? align: align,
??????????????????????????? attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
??????????????????????? )

??????????????????????? if j < data.entryCount && pe?.label != nil
??????????????????????? {
??????????????????????????? ChartUtils.drawText(
??????????????????????????????? context: context,
??????????????????????????????? text: pe!.label!,
??????????????????????????????? point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight),
??????????????????????????????? align: align,
??????????????????????????????? attributes: [
??????????????????????????????????? NSAttributedString.Key.font: entryLabelFont ?? valueFont,
??????????????????????????????????? NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
??????????????????????????? )
??????????????????????? }
??????????????????? }
??????????????????? else if drawXOutside
??????????????????? {
??????????????????????? if j < data.entryCount && pe?.label != nil
??????????????????????? {
??????????????????????????? ChartUtils.drawText(
??????????????????????????????? context: context,
??????????????????????????????? text: pe!.label!,
??????????????????????????????? point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight / 2.0),
??????????????????????????????? align: align,
??????????????????????????????? attributes: [
??????????????????????????????????? NSAttributedString.Key.font: entryLabelFont ?? valueFont,
??????????????????????????????????? NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
??????????????????????????? )
??????????????????????? }
??????????????????? }
??????????????????? else if drawYOutside
??????????????????? {
??????????????????????? ChartUtils.drawText(
??????????????????????????? context: context,
??????????????????????????? text: valueText,
??????????????????????????? point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight / 2.0),
??????????????????????????? align: align,
??????????????????????????? attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
??????????????????????? )
??????????????????? }
??????????????? }

??????????????? if drawXInside || drawYInside
??????????????? {
??????????????????? // calculate the text position
??????????????????? let x = labelRadius * sliceXBase + center.x
??????????????????? let y = labelRadius * sliceYBase + center.y - lineHeight

??????????????????? if drawXInside && drawYInside
??????????????????? {
??????????????????????? ChartUtils.drawText(
??????????????????????????? context: context,
??????????????????????????? text: valueText,
??????????????????????????? point: CGPoint(x: x, y: y),
??????????????????????????? align: .center,
??????????????????????????? attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
??????????????????????? )

??????????????????????? if j < data.entryCount && pe?.label != nil
??????????????????????? {
??????????????????????????? ChartUtils.drawText(
??????????????????????????????? context: context,
??????????????????????????????? text: pe!.label!,
??????????????????????????????? point: CGPoint(x: x, y: y + lineHeight),
??????????????????????????????? align: .center,
??????????????????????????????? attributes: [
??????????????????????????????????? NSAttributedString.Key.font: entryLabelFont ?? valueFont,
??????????????????????????????????? NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
??????????????????????????? )
??????????????????????? }
??????????????????? }
??????????????????? else if drawXInside
??????????????????? {
??????????????????????? if j < data.entryCount && pe?.label != nil
??????????????????????? {
??????????????????????????? ChartUtils.drawText(
??????????????????????????????? context: context,
??????????????????????????????? text: pe!.label!,
??????????????????????????????? point: CGPoint(x: x, y: y + lineHeight / 2.0),
??????????????????????????????? align: .center,
??????????????????????????????? attributes: [
??????????????????????????????????? NSAttributedString.Key.font: entryLabelFont ?? valueFont,
??????????????????????????????????? NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
??????????????????????????? )
??????????????????????? }
??????????????????? }
??????????????????? else if drawYInside
??????????????????? {
??????????????????????? ChartUtils.drawText(
??????????????????????????? context: context,
??????????????????????????? text: valueText,
??????????????????????????? point: CGPoint(x: x, y: y + lineHeight / 2.0),
??????????????????????????? align: .center,
??????????????????????????? attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
??????????????????????? )
??????????????????? }
??????????????? }

??????????????? if let icon = e.icon, dataSet.isDrawIconsEnabled
??????????????? {
??????????????????? // calculate the icon's position

??????????????????? let x = (labelRadius + iconsOffset.y) * sliceXBase + center.x
??????????????????? var y = (labelRadius + iconsOffset.y) * sliceYBase + center.y
??????????????????? y += iconsOffset.x

??????????????????? ChartUtils.drawImage(context: context,
???????????????????????????????????????? image: icon,
???????????????????????????????????????? x: x,
???????????????????????????????????????? y: y,
???????????????????????????????????????? size: icon.size)
??????????????? }

??????????????? xIndex += 1
??????????? }
??????? }
??? }
}

自定義HDPieChartView

//
//? HDPieChartView.swift
//
//? Created by Simon.Hua on 2021/11/16.
//

import UIKit

open class HDPieChartView: PieChartView {
?? ?
??? public override init(frame: CGRect)
??? {
??????? super.init(frame: frame)
??????? renderer = HDPieChartRenderer.init(withChart: self, animator: self.chartAnimator, viewPortHandler: self.viewPortHandler)
??? }
?? ?
??? required public init?(coder aDecoder: NSCoder) {
??????? fatalError("init(coder:) has not been implemented")
??? }
}


方法調(diào)用

只需要將原來初始化的地方垂攘,類名換成HDPieChartView就行了
if (!pieChartView) {

???????? pieChartView = [[HDPieChartView alloc] initWithFrame:superView.bounds];

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載哈打,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者匹耕。
  • 序言:七十年代末脯厨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子材部,更是在濱河造成了極大的恐慌照皆,老刑警劉巖伤疙,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悼吱,死亡現(xiàn)場離奇詭異慎框,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)后添,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門笨枯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事馅精⊙鲜龋” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵洲敢,是天一觀的道長漫玄。 經(jīng)常有香客問我,道長压彭,這世上最難降的妖魔是什么睦优? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮哮塞,結(jié)果婚禮上刨秆,老公的妹妹穿的比我還像新娘凳谦。我一直安慰自己忆畅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布尸执。 她就那樣靜靜地躺著家凯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪如失。 梳的紋絲不亂的頭發(fā)上绊诲,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機(jī)與錄音褪贵,去河邊找鬼掂之。 笑死,一個胖子當(dāng)著我的面吹牛脆丁,可吹牛的內(nèi)容都是我干的世舰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼槽卫,長吁一口氣:“原來是場噩夢啊……” “哼跟压!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起歼培,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤震蒋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后躲庄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體查剖,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年噪窘,在試婚紗的時候發(fā)現(xiàn)自己被綠了笋庄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖无切,靈堂內(nèi)的尸體忽然破棺而出荡短,到底是詐尸還是另有隱情,我是刑警寧澤哆键,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布掘托,位于F島的核電站,受9級特大地震影響籍嘹,放射性物質(zhì)發(fā)生泄漏闪盔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一辱士、第九天 我趴在偏房一處隱蔽的房頂上張望泪掀。 院中可真熱鬧,春花似錦颂碘、人聲如沸异赫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塔拳。三九已至,卻和暖如春峡竣,著一層夾襖步出監(jiān)牢的瞬間靠抑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工适掰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颂碧,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓类浪,卻偏偏與公主長得像载城,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子戚宦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容