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

相关推荐
符哥20084 小时前
一套基于Swift+MVVM为基础的iOS App 开发框架
swift
符哥20089 小时前
Swift 开发 iOS App 过程中写自定义控件的归纳总结
ios·cocoa·swift
锐意无限1 天前
Swift 扩展归纳--- UIView
开发语言·ios·swift
文件夹__iOS1 天前
AsyncStream 进阶实战:SwiftUI 全局消息流极简实现
ios·swiftui·swift
fendoudexiaoniao_ios4 天前
iOS 列表拖拽cell排序
ios·swift
CYpdpjRnUE4 天前
光伏电池PV建模及其基于Boost Buck电路的最大功率追踪MPPT算法研究及仿真效果探究
swiftui
大熊猫侯佩5 天前
Swift 6 驱魔实录:揭开 Combine 与 @Sendable 的“血色契约”
swift·block·combine·preconcurrency·sendable·mainactor·isolation
初级代码游戏5 天前
iOS开发 SwiftUI 15:手势 拖动 缩放 旋转
ios·swiftui·swift
ujainu5 天前
Flutter + OpenHarmony 游戏开发进阶:虚拟摄像机系统——平滑跟随与坐标偏移
开发语言·flutter·游戏·swift·openharmony
zhyongrui7 天前
SnipTrip 菜单 Liquid Glass 实现方案:结构、材质、交互与深浅色策略
ios·性能优化·swiftui·交互·开源软件·材质