如何为SwiftUI Chart中的每个BarMark分配独特颜色?
为SwiftUI Charts柱状图的每个BarMark分配独特颜色
要实现每个柱状条基于标签或TokenHolder的唯一属性显示不同颜色,有两种可靠的实现方式,以下是具体方案:
方法一:直接为每个BarMark绑定专属颜色
通过为每个BarMark添加foregroundStyle修饰符,结合一个根据唯一标识(比如标签、钱包地址)生成颜色的工具函数,就能为每个柱状条分配独特颜色。
步骤1:添加颜色生成工具函数
在CryptoChartView结构体中添加一个根据字符串生成唯一颜色的函数:
func colorForIdentifier(_ identifier: String) -> Color { var hash = 0 for char in identifier.utf8 { hash = Int(char) &+ (hash << 5) &- hash } let hue = Double(abs(hash) % 360) / 360.0 return Color(hue: hue, saturation: 0.7, brightness: 0.9) }
这个函数通过对字符串哈希计算生成固定色相的颜色,保证相同标识对应相同颜色,不同标识对应不同颜色。
步骤2:在BarMark中应用颜色
修改Chart内部的BarMark代码,添加foregroundStyle修饰符:
Chart { ForEach(Array(zip(labels, cryptoData)), id: \.1.id) { (label, holder) in BarMark( x: .value("Wallet", "\(label)"), y: .value("Amount", Double(holder.amount) ?? 0) ) .foregroundStyle(colorForIdentifier(label)) // 或者用TokenHolder的唯一属性,比如钱包地址: // .foregroundStyle(colorForIdentifier(holder.walletAddress)) } }
方法二:使用chartForegroundStyleScale映射系列颜色
如果希望通过SwiftUI Charts的内置样式系统管理颜色,可以为每个BarMark指定series参数,再通过chartForegroundStyleScale定义颜色映射规则。
修改Chart代码
Chart { ForEach(Array(zip(labels, cryptoData)), id: \.1.id) { (label, holder) in BarMark( x: .value("Wallet", "\(label)"), y: .value("Amount", Double(holder.amount) ?? 0), series: .value("Wallet Label", label) // 指定系列为标签 ) } } .chartForegroundStyleScale(range: labels.map { colorForIdentifier($0) }) // 或者手动指定颜色数组: // .chartForegroundStyleScale(range: [.red, .blue, .green, .orange, .purple, .pink, .teal, .indigo])
这里的series参数会将每个标签作为独立系列,chartForegroundStyleScale则为每个系列分配对应的颜色。如果不手动指定range,Charts会自动使用默认的颜色序列,但手动指定能更精准控制。
完整修改后的CryptoChartView代码
import SwiftUI import Charts struct CryptoChartView: View { let cryptoData: [TokenHolder] func generateAlphabetLabels(count: Int) -> [String] { let letters = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ") var labels = [String]() for i in 0..<count { let prefixIndex = i / letters.count let suffixIndex = i % letters.count let prefix = prefixIndex > 0 ? String(letters[prefixIndex - 1]) : "" let suffix = String(letters[suffixIndex]) labels.append(prefix + suffix) } return labels } func colorForIdentifier(_ identifier: String) -> Color { var hash = 0 for char in identifier.utf8 { hash = Int(char) &+ (hash << 5) &- hash } let hue = Double(abs(hash) % 360) / 360.0 return Color(hue: hue, saturation: 0.7, brightness: 0.9) } var body: some View { let labels = generateAlphabetLabels(count: cryptoData.count) Chart { ForEach(Array(zip(labels, cryptoData)), id: \.1.id) { (label, holder) in BarMark( x: .value("Wallet", "\(label)"), y: .value("Amount", Double(holder.amount) ?? 0) ) .foregroundStyle(colorForIdentifier(label)) } } .chartScrollableAxes(.horizontal) .chartYAxis { AxisMarks(values: .automatic) { value in AxisGridLine(centered: true) AxisTick() AxisValueLabel() { if let intValue = value.as(Int.self) { Text(String.formatAmount(String(intValue))) } } } } } } // 补充TokenHolder结构体定义(原代码中缺失) struct TokenHolder: Identifiable { let id = UUID() let amount: String let walletAddress: String let usdAmount: String } extension String { static func formatAmount(_ amount: String) -> String { // 实现你的金额格式化逻辑 return amount } } // 示例数据 extension CryptoChartView { static let sampleData = [ TokenHolder(amount: "500000000000.000000000000000000", walletAddress: "0x1111111111111111111111111111111111111111", usdAmount: "75000000.00"), TokenHolder(amount: "450000000000.000000000000000000", walletAddress: "0x2222222222222222222222222222222222222222", usdAmount: "67500000.00"), TokenHolder(amount: "400000000000.000000000000000000", walletAddress: "0x3333333333333333333333333333333333333333", usdAmount: "60000000.00"), TokenHolder(amount: "350000000000.000000000000000000", walletAddress: "0x4444444444444444444444444444444444444444", usdAmount: "52500000.00"), TokenHolder(amount: "300000000000.000000000000000000", walletAddress: "0x5555555555555555555555555555555555555555", usdAmount: "45000000.00"), TokenHolder(amount: "250000000000.000000000000000000", walletAddress: "0x6666666666666666666666666666666666666666", usdAmount: "37500000.00"), TokenHolder(amount: "200000000000.000000000000000000", walletAddress: "0x7777777777777777777777777777777777777777", usdAmount: "30000000.00"), TokenHolder(amount: "150000000000.000000000000000000", walletAddress: "0x8888888888888888888888888888888888888888", usdAmount: "22500000.00") ] }
注意事项
- 如果选择方法二,确保
series参数传入的是唯一标识(比如标签或钱包地址),这样Charts才能为每个系列分配独立颜色。 - 颜色生成函数可以根据需求调整饱和度、亮度参数,或者改用预设颜色数组,让配色更符合应用风格。
内容的提问来源于stack exchange,提问作者Retro Boomin
相关产品推荐
相关产品推荐

