iOS Charts(Daniel Gindi):两个LineChartDataSet颜色设置失效问题
iOS Charts 折线图选中后颜色显示异常修复
问题描述
使用Daniel Gindi的iOS Charts构建折线图,初始状态加载单个渐变颜色数据集。选中图表上的数值点后,期望选中点右侧的折线显示为红色,但实际效果相反:左侧折线变成红色,右侧仍保留原渐变颜色。
相关代码
单元格代码
class GraphTableViewCell: UITableViewCell { @IBOutlet weak var yieldLabel: UILabel! @IBOutlet weak var yieldPercentLabel: UILabel! @IBOutlet weak var lineChart: LineChartView! @IBOutlet weak var graphButtonView: AssetGraphButtonView! @IBOutlet weak var endDateLabel: UILabel! @IBOutlet weak var startDateLabel: UILabel! var selectionView: AssetGraphSelectionView! var viewModel: GraphViewModelType! var set: LineChartDataSet! var set1: LineChartDataSet! var marker = BalloonMarker(color: .red, font: UIFont.systemFont(ofSize: 15), textColor: .white, insets: UIEdgeInsets(top: 5, left: 5, bottom: 10, right: 3)) override func awakeFromNib() { super.awakeFromNib() } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } override func layoutSubviews() { super.layoutSubviews() } func config(with viewModel: GraphViewModelType) { self.viewModel = viewModel yieldLabel.attributedText = viewModel.titleAttributeText yieldPercentLabel.attributedText = viewModel.yielAttributeText startDateLabel.attributedText = viewModel.startDateAttributeText endDateLabel.attributedText = viewModel.endDateAttributeText graphButtonView.confgiureCell(with: self.viewModel.btnData) setUpChart() } func setUpChart() { lineChart.delegate = self lineChart.noDataText = "No Data Available" lineChart.rightAxis.enabled = false lineChart.leftAxis.enabled = false lineChart.xAxis.enabled = false lineChart.legend.enabled = false lineChart.xAxis.drawGridLinesEnabled = false lineChart.drawMarkers = true lineChart.doubleTapToZoomEnabled = false lineChart.pinchZoomEnabled = false lineChart.scaleXEnabled = false lineChart.scaleYEnabled = false marker.chartView = lineChart marker.minimumSize = CGSize(width: 28, height: 20) lineChart.marker = marker let dataSets = viewModel.getLineChartDataSet() let data = LineChartData(dataSets: dataSets) data.setValueFont(.systemFont(ofSize: 7, weight: .light)) lineChart.data = data } } extension GraphTableViewCell: ChartViewDelegate { func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) { let transform = lineChart.getTransformer(forAxis: .left) let point = transform.pixelForValues(x: highlight.x, y: highlight.y) print("point : x = \(point.x) y = \(point.y)") let color = self.lineChart.colorOfPoint(point: point) marker.color = color let dataSets = viewModel.chartValueSelected(entry: entry) lineChart.data = dataSets } }
ViewModel代码
final class GraphTableViewCellViewModel: GraphViewModelType { var startDateAttributeText = NSMutableAttributedString() var endDateAttributeText = NSMutableAttributedString() var titleAttributeText = NSMutableAttributedString(string: "", attributes: [NSAttributedString.Key.font : UIFont(name: "Orion-Bold", size: 14)!, NSAttributedString.Key.foregroundColor : UIColor.black]) var yielAttributeText = NSMutableAttributedString(string: "\(String(format: "%.2f%%", abs(14)))", attributes: [NSAttributedString.Key.font : UIFont(name: "Orion-Bold", size: 14)!, NSAttributedString.Key.foregroundColor : UIColor.green]) let disposeBag = DisposeBag() var btnData: [AssetGraphButtonViewViewModel] var data: TwrGraph var dataSet = [LineChartDataSet]() var set: LineChartDataSet! var set1: LineChartDataSet! init(with data: TwrGraph) { btnData = AssetGraphViewModel(security: nil).assetGraphData self.data = data startDateAttributeText = NSMutableAttributedString(string: data.startDate, attributes: [NSAttributedString.Key.font : UIFont(name: "Orion-Regular", size: 12)!, NSAttributedString.Key.foregroundColor : ColorName.warmGreyTwo]) endDateAttributeText = NSMutableAttributedString(string: data.endDate, attributes: [NSAttributedString.Key.font : UIFont(name: "Orion-Regular", size: 12)!, NSAttributedString.Key.foregroundColor : ColorName.warmGreyTwo]) } func getChartDataPoints(dataPoints: [String], values: [Double]) -> [ChartDataEntry] { var dataEntries: [ChartDataEntry] = [] for count in (0..<dataPoints.count) { dataEntries.append(ChartDataEntry.init(x: Double(count), y: values[count])) } return dataEntries } func getLineChartDataSet() -> [LineChartDataSet] { let dataWeeklyDate = self.data.weeklyGraph.map { $0.date } let dataWeeklyYield = self.data.weeklyGraph.map { $0.yield } let dataPoints = getChartDataPoints(dataPoints: dataWeeklyDate, values: dataWeeklyYield) set = LineChartDataSet(entries: dataPoints, label:"" ) setup(set) return [set] } func setup(_ dataSet: LineChartDataSet) { dataSet.drawHorizontalHighlightIndicatorEnabled = false dataSet.drawVerticalHighlightIndicatorEnabled = true dataSet.isDrawLineWithGradientEnabled = true dataSet.fillAlpha = 0.15 dataSet.lineWidth = 2 dataSet.circleRadius = 0 dataSet.drawCircleHoleEnabled = false dataSet.drawCirclesEnabled = false dataSet.drawValuesEnabled = false dataSet.highlightColor = .blue let rightColor = [ChartColorTemplates.colorFromString("#FA3A7A"), ChartColorTemplates.colorFromString("#C257B1"), ChartColorTemplates.colorFromString("#8B73E8")] dataSet.colors = rightColor dataSet.gradientPositions = [0, 40, 100] let gradientColors = [ChartColorTemplates.colorFromString("#FC4684").cgColor, ChartColorTemplates.colorFromString("#D8D8D8").cgColor] let colorLocations:[CGFloat] = [1.0, 0.0] if let gradient = CGGradient(colorsSpace: nil, colors: gradientColors as CFArray, locations: colorLocations) { dataSet.fill = LinearGradientFill(gradient: gradient, angle: 90.0) } dataSet.drawFilledEnabled = true } func updateSetAfterTouch(_ dataSet: LineChartDataSet) { dataSet.drawHorizontalHighlightIndicatorEnabled = false dataSet.drawVerticalHighlightIndicatorEnabled = true dataSet.fillAlpha = 0.15 dataSet.lineWidth = 2 dataSet.circleRadius = 0 dataSet.drawCircleHoleEnabled = false dataSet.drawCirclesEnabled = false dataSet.drawValuesEnabled = false dataSet.colors = [.red] } func chartValueSelected(entry: ChartDataEntry) -> LineChartData { return updateSet(with: entry) } func updateSet(with entry: ChartDataEntry) -> LineChartData { var dataEntries: [ChartDataEntry] = [] var dataEntries1: [ChartDataEntry] = [] for count in (0..<self.data.weeklyGraph.count) { if count < Int(entry.x) { dataEntries.append(ChartDataEntry.init(x: Double(count), y: self.data.weeklyGraph[count].yield)) } else { dataEntries1.append(ChartDataEntry.init(x: Double(count), y: self.data.weeklyGraph[count].yield)) } } set = LineChartDataSet(entries: dataEntries, label:"" ) set1 = LineChartDataSet(entries: dataEntries1, label:"" ) setup(set) updateSetAfterTouch(set1) let data = LineChartData(dataSets: [set1, set]) return data } }
问题原因
在updateSet(with:)方法中,创建LineChartData时传入的数据集顺序错误:
set是选中点左侧的原渐变数据集,set1是选中点右侧的红色数据集- Charts按数组顺序绘制数据集,后添加的数据集会覆盖先添加的。原代码中
[set1, set]导致左侧的渐变数据集覆盖了右侧的红色数据集,视觉上呈现左侧变红的错误效果。
解决方案
修正LineChartData的数据集顺序,将左侧渐变数据集放在前面,右侧红色数据集放在后面,确保红色数据集绘制在上方:
func updateSet(with entry: ChartDataEntry) -> LineChartData { // ... 其他代码保持不变 ... setup(set) updateSetAfterTouch(set1) // 调整顺序:先绘制左侧渐变数据集,再绘制右侧红色数据集 let data = LineChartData(dataSets: [set, set1]) return data }
额外优化
可以移除updateSetAfterTouch方法中重复的配置代码,直接复用setup方法后再覆盖颜色属性,减少冗余:
func updateSetAfterTouch(_ dataSet: LineChartDataSet) { // 复用基础配置 setup(dataSet) // 覆盖为红色 dataSet.colors = [.red] dataSet.isDrawLineWithGradientEnabled = false }
内容的提问来源于stack exchange,提问作者ironRoei
相关产品推荐
相关产品推荐

