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

如何为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:24:57