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-)

相关推荐
奶糖的次元空间1 天前
iOS 学习笔记 - SwiftUI 和 简单布局
ios·swift
2501_915918413 天前
有没有Xcode 替代方案?在快蝎 IDE 中完成 iOS 开发的过程
ide·vscode·ios·个人开发·xcode·swift·敏捷流程
songgeb3 天前
Compositional layout in iOS
ios·swift·设计
1024小神3 天前
记录xcode项目swiftui配置APP加载启动图
前端·ios·swiftui·swift
WaywardOne3 天前
SwiftUI中修饰符的顺序直接影响视图最终效果
ios·swiftui·ui kit
wjm0410065 天前
ios学习路线-- swift基础2
学习·ios·swift
游戏开发爱好者85 天前
如何使用Instruments和Keymob进行Swift应用性能优化分析
开发语言·ios·性能优化·小程序·uni-app·iphone·swift
游戏开发爱好者87 天前
新的 iOS 开发工具体验,在快蝎 IDE 里完成应用开发与真机调试
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
东坡肘子7 天前
50 岁的苹果和 51 岁的我 -- 肘子的 Swift 周报 #127
人工智能·swiftui·swift
denggun123457 天前
Sendable 协议-Swift 结构化并发的核心安全保障
ios·swift