SwiftUI Charts 入门:从零到一,笑谈“柱”状人生(二)

概述

从 iOS 16 开始,Apple 为小伙伴们带来了全新的 SwiftUI Charts 框架,让我们可以用极少的代码便捷地绘制折线图、柱状图、饼图以及各种图,可谓"画龙点睛,一步登天"。

本系列文章将带宝子们从无到有,逐步拆解示例 TodayInYearsSetbacksComparisonChart 的源代码,并着重揭示几个开发中的"鬼斧神工"与"隐藏套路"。

在本篇博文中,您将学到如下内容:

    1. 倾斜的秘密:用 Annotation 自定义 X 轴标签
  • 2.1 自定义 x 轴标签
  • 2.2 拯救者:Annotation 出马!

想用 Charts 为自己精妙绝伦的 App 如虎添翼吗?看这篇就对啦! 无需等待,让我们马上开始 Charts 大冒险吧! Let's go!!!;)


2. 倾斜的秘密:用 Annotation 自定义 X 轴标签

2.1 自定义 x 轴标签

对于前一篇文章的问题,我们可以通过自己绘制图表的 x 轴标签来解决:

swift 复制代码
Chart {...}
.chartXAxis {
    AxisMarks { value in
        if let yearIdx = value.as(Int.self), yearIdx < sortedYears.count {
            let year = sortedYears[yearIdx]
            AxisValueLabel("\(year)")
            AxisGridLine()
        }
    }
}

在上面的代码中,我们使用图表的 chartXAxis 修改器"毅然决然"的抛弃了默认 x 轴标签,换成了自己 Nice 的年份显示:

不过,上面的结果没有显示所有的年份,这不是我们想要的。幸运的是,这可以通过 AxisMarks 中值的另一种构造器来"勉强"解决:

swift 复制代码
Chart {...}
.chartXAxis {
    AxisMarks(values: .stride(by: 1)) { value in
        if let yearIdx = value.as(Int.self), yearIdx < sortedYears.count {
            let year = sortedYears[yearIdx]
            AxisValueLabel("\(year)")
            AxisGridLine()
        }
    }
}

为什么说是"勉强"解决呢?因为即使这样,Charts 也总是忽略绘制最后一个年份(2017年):

所以,我们又该何去何从呢?

2.2 拯救者:Annotation 出马!

幸运的是,Charts 提供了一个 annotation 修改器方法,我们可以用它来进一步定制与图表元素相关的显示信息:

要达到用 annotation 模拟图表 x 轴标签的目的,我们需要解决两个小麻烦:

  1. 图片元素过分拥挤可能导致标签显示重叠
  2. 如何避免 annotation 下方多余的 y 轴标签?

为了让小伙伴们更清楚问题之所在,我们先用 annotation 实现一个初级版本一窥究竟:

swift 复制代码
Chart {
    ForEach(sortedYears.indices, id: \.self) { yearIndex in
        
        let year = sortedYears[yearIndex]
        let sbCount = sbCountInYears[year]!
        let isThisYear = TimeMachine.shared.now.isSameYear(year)
        
        BarMark(x: .value("年份序号", yearIndex), y: .value("次数", sbCount))
            .foregroundStyle(isThisYear ? .blue : .red)
            .annotation(position: .bottom, alignment: .center, spacing: 10) {
                Text(verbatim: "\(year)")
                    .foregroundStyle(.gray)
                    .font(.footnote)
            }
    }
}
.chartXAxis(.hidden)

在上面的代码中,我们使用 annotation 完全替代了原本"不称职"的 x 轴标签,值得注意的是:我们需要使用 chartXAxis(.hidden) 修改器来隐藏默认的 x 轴标签。

运行结果如下所示:

看到我们之前所说的那两个麻烦了吗?

在这里,我们可以通过两种技术来解决它们,分别是标签倾斜定制 y 轴标签

swift 复制代码
Chart {
    ForEach(sortedYears.indices, id: \.self) { yearIndex in
        
        let year = sortedYears[yearIndex]
        let sbCount = sbCountInYears[year]!
        let isThisYear = TimeMachine.shared.now.isSameYear(year)
        
        BarMark(x: .value("年份序号", yearIndex), y: .value("次数", sbCount))
            .foregroundStyle(isThisYear ? .blue : .red)
            .annotation(position: .bottom, alignment: .center, spacing: 10) {
                Text(verbatim: "\(year)")
                    .foregroundStyle(.gray)
                    .font(.footnote)
                    .rotationEffect(.degrees(45))
                    .offset(x: 15)
            }
    }
}
.chartXAxis(.hidden)
.chartYAxis {
    AxisMarks { value in
        if let y = value.as(Int.self), y >= 0 {
            AxisValueLabel("\(y)")
            AxisGridLine()
        }
    }
}

在上面的代码中,我们主要做了如下几件事:

  1. 使用 rotationEffectoffset 修改器使 annotation 中的 Text 文本略微倾斜,让各个标签拉开空档;
  2. 使用自定义 y 轴标签忽略 0 以下标签;
  • .annotation(position: .bottom):在柱子底部添加自定义视图;
  • 倾斜 45° :用 .rotationEffect
  • .offset(x: 15):微调位置,防止与坐标轴重叠。

再次编译运行,现在效果是不是好多了呢?

如此"锦上添花、一举两得",既能显示完整年份,又不会压缩布局,何乐而不为呢?

在下一篇博文中,我们将继续劈风斩浪,让一个个图表布局上的"多事之秋"成为我们的"刀下冤魂",敬请期待吧!

总结

在本篇博文中,我们讨论了如何利用图表 Annotation 和定制标签绘制,来避免图表元素重叠和过滤不需要的轴标签。

感谢观赏,我们下一篇再会啦!8-)

相关推荐
大熊猫侯佩43 分钟前
代码精讲:WWDC 25 @Animatable 宏 —— SwiftUI 动画的新突破
swiftui·swift·wwdc
大熊猫侯佩14 小时前
SwiftUI Charts 入门:从零到一,笑谈“柱”状人生(三)
swiftui·swift·apple
大熊猫侯佩14 小时前
SwiftUI Charts 入门:从零到一,笑谈“柱”状人生(一)
swiftui·swift·apple
归故里1 天前
[swift] 用泛型整合 Codable 和 文件读写!
swift
iOS阿玮1 天前
凭一己之力干穿一个品牌,互联网+时代口碑比以前更重要了!
uni-app·app·apple
杂雾无尘1 天前
Vision Pro 新手教学:SwiftUI 实现 3D 应用的技巧,基础篇
ios·swiftui·visionos
不会写代码的丝丽2 天前
iOS 队列与线程
swift
Swift社区3 天前
从字符串中“薅出”最长子串:LeetCode 340 Swift 解法全解析
算法·leetcode·swift
东吴贾诩3 天前
[WWDC 2025] 用新设计构建一个SwiftUI应用程序
swiftui·wwdc