You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:36:32