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

iOS-Chart柱状图0值柱子不显示:如何设置固定最小高度?

解决iOS-Chart中0值Bar不显示的稳定方案

针对你遇到的0值柱子无法显示、修改渲染器效果不稳定的问题,提供两种稳定可行的方案:


方案一:数据预处理+自定义值格式化器(简单易实现)

核心思路是将0值替换为极小的非零值,保证柱子能显示,同时通过格式化器让数值显示为0,完全不影响用户感知。

1. 修改数据条目生成逻辑

在entryData方法中,把所有0值替换为极小值(比如0.001):

func entryData(values: [Double]) -> [BarChartDataEntry] {
    var barDataEntries: [BarChartDataEntry] = []
    for i in 0 ..< values.count {
        // 将0替换为极小值,确保柱子能被渲染
        let yValue = values[i] == 0 ? 0.001 : values[i]
        let barDataEntry = BarChartDataEntry(x: Double(i), y: yValue)
        barDataEntries.append(barDataEntry)
    }
    return barDataEntries
}

2. 自定义值格式化器

创建格式化器,把极小值显示为0,其他数值正常格式化:

class ZeroValueFormatter: NSObject, IValueFormatter {
    private let numberFormatter: NumberFormatter
    
    init(numberFormatter: NumberFormatter) {
        self.numberFormatter = numberFormatter
        super.init()
    }
    
    func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
        // 小于0.01的数值统一显示为0
        if value < 0.01 {
            return "0"
        }
        return numberFormatter.string(from: NSNumber(value: value)) ?? "\(value)"
    }
}

3. 替换原有的值格式化器

在setBarData方法中使用自定义格式化器:

func setBarData(barChartView: BarChartView, barChartDataEntries: [BarChartDataEntry]) {
    let barChartdataSet = BarChartDataSet(entries: barChartDataEntries, label: "text")
    
    let numberFormatter = NumberFormatter()
    numberFormatter.numberStyle = .decimal
    numberFormatter.locale = Locale.current
    // 使用自定义格式化器替换默认实现
    let valuesFormatter = ZeroValueFormatter(numberFormatter: numberFormatter)
    barChartdataSet.valueFormatter = valuesFormatter
    
    let barChartData = BarChartData(dataSet: barChartdataSet)
    barChartData.barWidth = Double(0.3)
    barChartView.data = barChartData
}

方案二:自定义BarChartRenderer(精准控制高度)

如果需要完全固定0值柱子的像素高度(不受Y轴数据范围影响),可以自定义渲染器直接控制绘制逻辑。

1. 自定义渲染器类

class CustomBarChartRenderer: BarChartRenderer {
    // 0值柱子的固定高度(单位:pt)
    private let zeroBarHeight: CGFloat = 3
    
    override func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int) {
        guard let barData = dataProvider?.barData,
              let trans = dataProvider?.getTransformer(forAxis: dataSet.axisDependency),
              let chartBottomPixel = trans.pixelForValues(x: 0, y: dataProvider?.chartYMin ?? 0)?.y else {
            return
        }
        
        let phaseY = animator.phaseY
        let barWidth = barData.barWidth
        let barHalfWidth = barWidth / 2.0
        
        context.saveGState()
        
        for j in 0..<dataSet.entryCount {
            guard let entry = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
            
            let x = entry.x
            let y = entry.y
            
            // 计算柱子的左右边界
            let left = x - barHalfWidth
            let right = x + barHalfWidth
            var barRect = CGRect(x: left, y: 0, width: right - left, height: 0)
            
            if y != 0 {
                // 非0值柱子正常绘制
                var top = y >= 0 ? y : 0.0
                var bottom = y <= 0 ? y : 0.0
                top *= phaseY
                bottom *= phaseY
                barRect = CGRect(x: left, y: bottom, width: right - left, height: top - bottom)
                trans.rectValueToPixel(&barRect)
            } else {
                // 0值柱子绘制固定高度的矩形
                trans.rectValueToPixel(&barRect)
                barRect = CGRect(
                    x: barRect.origin.x,
                    y: chartBottomPixel - zeroBarHeight,
                    width: barRect.size.width,
                    height: zeroBarHeight
                )
            }
            
            // 设置柱子颜色并绘制
            context.setFillColor(dataSet.color(atIndex: j).cgColor)
            context.fill(barRect)
        }
        
        context.restoreGState()
    }
}

2. 配置图表使用自定义渲染器

在图表初始化代码中(比如awakeFromNib或initChart)设置渲染器:

// 替换默认渲染器
self.monthlyBarChart.renderer = CustomBarChartRenderer(
    dataProvider: monthlyBarChart,
    animator: monthlyBarChart.chartAnimator,
    viewPortHandler: monthlyBarChart.viewPortHandler
)

方案对比

  • 方案一:无需修改渲染逻辑,兼容性好,适合大多数场景,极小值对Y轴缩放的影响可以忽略不计。
  • 方案二:精准控制0值柱子的像素高度,完全不受数据最大值影响,适合对UI精度要求高的场景。

内容的提问来源于stack exchange,提问作者KimJitae

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:23:09