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
相关产品推荐
相关产品推荐

