【编者按】本文作者 Joyce Echessa 是渥合数位服务创办人,毕业于台湾大学,近年来专注于协助客户进行 App 软体以及网站开发。文中作者通过示例介绍用 ios-charts 库创建简易美观的图表,有助于开发者在应用中生动形象地向用户展示数据。本文系 OneAPM 工程师编译整理:
呈现大量数据时,比起表格中一行行枯燥的数据,使用图表来形象地表示数据可以帮助用户更好地理解。在图表中,不需要通读所有数据资料,便能很容易地了解数据模式,从而获取关键信息。图表的使用在商业 App 和健身 App 中非常常见。
本篇文章中,我们主要介绍由 Daniel Cohen Gindi 开发的 ios-charts library。ios-charts 是由 Philipp Jahoda 建立的,是非常流行的 Android 库 MPAndroidChart 的 iOS 端口。有了这个库,你可以方便快捷地在应用中添加不同类型的图表。仅需寥寥几行代码,就可以制作出功能齐备、交互性强的图表,并且高度可定制。
函数库的主要特征:
8种不同的图表类型;
两个轴的缩放(用触控手势、分轴缩放或捏拉缩放);
拖拽/平移(用触控手势);
图表结合(线形图、柱形图、离散图、K 线图、气泡图);
双(分开的)Y 轴;
手指画图(用触控手势将数值画入图表);
数值突出显示(自定义弹出视图);
多个/分离的轴;
储存图表到相册/以 PNG/JPEG 格式输出;
预定义颜色模板;
图例(可自动生成,可自定义);
自定义轴(包括 X 和Y 轴);
动画(在 X 轴和 Y 轴上建立动画);
界限(提供额外信息,比如最大值等);
全方位自定义(上色、字体、图例、颜色、背景、手势、虚线等)。
开始吧!
首先、下载本篇文章将会用到的初始示例——名为 iOSChartsDemo 的简易应用。应用运行时,你会看到有两个项目的表格:条形图和其他图表。当点击项目时,会得到空白的视图。在本例中,笔者已创建了要用的两个视图控制器:BarChartViewController 和 ChartsViewController。
接着,我们添加函数库到项目中。你可以用 CocoaPods 安装该库,这里我们直接手动安装。
下载 ios-charts 项目,这个 zip 文件包含了函数库(名为 Charts 的文件夹)和一个示例项目(名为 ChartsDemo)。如果你想了解更多关于函数库的知识,示例项目是很棒的资源。
解压缩已下载的文件,并将 Charts 文件复制粘贴到你项目(iOSChartsDemo)的根目录下。在 Finder 中打开Charts文件,并将 Charts.xcodeproj 拖拽到 Xcode 项目中。结构如下图所示。
接着从项目导航中选择你的项目,并确保该 iOSChartsDemo 目标被选中。在右边的常规选项卡中找到 Embedded Binaries 部分,点击该部分的+
号添加图表框架。从列表中选择 Charts.framework 并点击 Add。
如果你想在 Objective-C 中使用函数库,请参考使用说明。
用 Command-B 或选择 Product > Build 来生成项目。如果不这样做,当你导入 Charts 框架到你的项目时,Xcode 会报错——无法加载 Charts 底层模块。
现在开始创建第一个图表。
创建一个柱形图
打开 BarChartViewController.swift 文件,添加以下声明。
import Charts
打开故事板文件。我们需要添加用来显示图表的视图。从文档纲要中选择 Bar Chart View Controller,并在属性检查器中取消 Extend Edges 的 Under Top Barsin 选项。我们不希望图表自动延伸至导航栏下方。
接着拖拽一个视图到 Bar Chart View Controller 中,并按下图定位边界。该视图为控制器中主视图的子视图。
视图被选中后,在识别检查器中将它的类设为 BarChartView。再使用助理编辑器,加入视图的 outlet 到 BarChartViewController 类,并命名为 outletbarChartView。在 BarChartViewController 类中添加下列代码。
@IBOutlet weak var barChartView: BarChartView!
运行项目,并从表格中选择柱形图,你可能会得到视图提示信息:无可用的图表数据。
如果在没有数据来产生图表时,你想在空白状态显示其他的信息,这时候可以自定义这个提示信息。在 viewDidLoad()函数底部,加入下列代码。
运行该项目,可以看到自定义的提示信息。
你可以为下面信息进一步添加描述。这可以用来向用户解释,为什么图表是空的,他们需要获取数据来生成图表。例如:健身 App 应该让用户知道在整理图表分析之前,他们需要先记录跑步数据。
barChartView.noDataTextDescription = "GIVE REASON"
添加下面的属性到该类。我们用它来存储一些图表的模拟数据。
var months: [String]!
将下面的函数添加到该类,用以建立图表。
func setChart(dataPoints: [String], values: [Double]) {
barChartView.noDataText = "You need to provide data for the chart."
}
请注意,我曾经在 viewDidLoad()函数中添加了声明。现在从 viewDidLoad()中移除该声明。我们将用 setChart()来自定义图表。
在 viewDidLoad()中,添加以下内容到函数底部。
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
let unitsSold = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0, 4.0, 18.0, 2.0, 4.0, 5.0, 4.0]
setChart(months, values: unitsSold)
我们设置一些模拟数据,给出一些产品一年中每个月售出的单位数。然后,我们将数据传给 setChart()。
让一个图表显示数据,我们还需创建一个 BarChartData 对象,并将其设置为 barChartView 的数据属性。添加下面的代码到 setChart()函数底部。
var dataEntries: [BarChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = BarChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(yVals: dataEntries, label: "Units Sold")
let chartData = BarChartData(xVals: months, dataSet: chartDataSet)
barChartView.data = chartData
以上代码中,我们创建了一个 BarChartDataEntry 对象的数组。BarChartDataEntry 初始化需要每个数据项的值、其对应的项目索引以及一个任意的标签。
随后,我们使用这个对象创建 BarChartDataSet,主要用来传递 BarChartDataEntry 对象的数组,以及描述数据的标签。
最后,我们用它来创建一个 BarChartData 对象,用来设定我们图表视图的数据。
运行该应用,可以看到如下图所示有数据的柱形图。
你可以为出现在视图右下方的图表设置说明。默认情况下,文本可用来设置「说明」,该说明会出现在图片上。参考 ofMPAndroidChart 文档,你可以更改描述的位置,但看一下 iOS 的 API,这并没有包括在内。函数库仍在维护,所以可能会在之后添加。如果你想改变描述的位置,你可以修改 ChartViewBase 类(是 BarChartView 类的子类)中的 drawDescription(上下文)函数。
针对本应用,我们移除描述文本。在 setChart()函数的底部添加下列内容,将描述文本设为空字符串。
barChartView.descriptionText = ""
自定义图表
你可以修改一些属性来自定义图表视图的外观。下面我们来具体介绍,你也可以浏览文档看看哪些可以自定义。
首先,我们修改柱形图的默认颜色。添加下列设置到 setChart()函数的底部。
chartDataSet.colors = [UIColor(red: 230/255, green: 126/255, blue: 34/255, alpha: 1)]
以上代码设置了与数据相关的颜色。将该设定给 UIColor 对象数组。因此只要数组中有一种颜色,所有的实体均可用。
如果你想给每一个数据对象设置不同的颜色,那么你需要提供更多的颜色,本例中需要12种。如果你的颜色数量少于实体总数,那么从坐到右将不同的颜色分配给柱形图,直到颜色用完后重新开始分配。
API 中也自带一些预定义颜色模板,你可以用它来为数据项设定不同颜色,它们包括:
ChartColorTemplates.liberty()
ChartColorTemplates.joyful()
ChartColorTemplates.pastel()
ChartColorTemplates.colorful()
ChartColorTemplates.vordiplom()
如下所示,使用 ChartColorTemplates.colorful()模板。
chartDataSet.colors = ChartColorTemplates.colorful()
如下所示修改 X 轴标签的位置。
barChartView.xAxis.labelPosition = .Bottom
现在标签在图表底部。
按照以下办法可以修改图表的背景色。
barChartView.backgroundColor = UIColor(red: 189/255, green: 195/255, blue: 199/255, alpha: 1)
根据上述设定,你会看到如下所示的界面。
动画
你可以为图表设定一些动画,使之更加生动活泼。你可以使用三种主要的动画类型方法,可以同时让 XY 轴或者分别某个轴产生动画。
animate(xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval)
animate(xAxisDuration: NSTimeInterval)
animate(yAxisDuration: NSTimeInterval)
你可以加入任意的 ChartEasingOption 到以上函数。选项如下:
Linear
EaseInQuad
EaseOutQuad
EaseInOutQuad
EaseInCubic
EaseOutCubic
EaseInOutCubic
EaseInQuart
EaseOutQuart
EaseInOutQuart
EaseInQuint
EaseOutQuint
EaseInOutQuint
EaseInSine
EaseOutSine
EaseInOutSine
EaseInExpo
EaseOutExpo
EaseInOutExpo
EaseInCirc
EaseOutCirc
EaseInOutCirc
EaseInElastic
EaseOutElastic
EaseInOutElastic
EaseInBack
EaseOutBack
EaseInOutBack
EaseInBounce
EaseOutBounce
EaseInOutBounce
添加下行内容到 setChart()函数。
运行应用,柱形图以动画的形式加入视图。我们同时为两个轴都设置2秒的动画。
修改上述状态为:
barChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .EaseInBounce)
你会看到这行的特效如下。
界限
界限是针对所有线形图、柱形图和离散图的附加功能。它允许在图表中显示额外的线条为特定轴(X 或 Y 轴)加限制。这额外的线用来设定数据的目标值,帮助用户更容易了解是否达到界限。
要在图表中加入界限,可以添加以下代码到 setData()函数中。
let ll = ChartLimitLine(limit: 10.0, label: "Target")
barChartView.rightAxis.addLimitLine(ll)
运行该应用,你可以看到一条红线,标记在单位10左右。上面的代码中,我们在界限上添加了一个标签。但是 ChartLimitLine 有另一个没有添加标签的初始化函数,如果不想加的话可以省略。
触控事件
如果运行应用,你会发现通过默认的捏拉缩放和双击来进行缩放。此外,如果某个柱形条被单击,该柱形条会突出显示。很棒的是无需自己再编代码就能使用该功能,除非你想添加更多的功能,比如当用户单击柱形条时有其他响应。
为了检测图表内的选择,我们将使用 ChartViewDelegate 协议。
修改该类的声明如下。
class BarChartViewController: UIViewController, ChartViewDelegate {
在调用 super.viewDidLoad()后面添加下列代码到 viewDidLoad()。
barChartView.delegate = self
添加下面的函数到该类。
func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, dataSetIndex: Int, highlight: ChartHighlight) {
println("\(entry.value) in \(months[entry.xIndex])")
}
当图表视图中的值被选中时,会调用上述函数。这里我们打印出被选中的月份和值。
保存图表
你可以将图表的当前状态保存为图像。可以选择将它保存到相机胶卷或者重新设置一个保存路径。
首先,我们将添加一个保存按钮到图表视图。打开故事板文件,并找到柱形图表视图控制器。拖动导航项目到视图控制器的导航栏,然后拖动柱形按钮项,并将其放置于导航项目的右上角。删除属性检查器中的导航项目的标题属性中的「标题」文本。选择柱形按钮项,并设置其标识便于保存到属性检查器。可以看到如下界面。
接着为按钮创建一个消息响应,命名为 saveChart,添加以下代码到 BarChartViewController 类中。
@IBAction func saveChart(sender: UIBarButtonItem) {
}
按照下列代码修改上面的方法。
@IBAction func saveChart(sender: UIBarButtonItem) {
barChartView.saveToCameraRoll()
}
执行该程序后,当点击保存按钮时,图表图像讲保存到相册,可用 Photos 应用浏览。
下列代码可以重新设置保存路径。
barChartView.saveToPath(path: String, format: ChartViewBase.ImageFormat, compressionQuality: Double)
图片格式可能是 .JPEG或 .PNG,该 compressionQuality 是一种无损格式(JPEG)的压缩质量。
更多图表
现在我们看一下其他几个图表。大部分我们都看过了,所以不再过多赘述。
首先,在故事板文件中找到图表视图控制器,在识别检查器中,设定视图的标签为 Pie Chart View 的类为 PieChartView。
如下所示修改 ChartsViewController 类。
import UIKit
import Charts
class ChartsViewController: UIViewController {
@IBOutlet weak var lineChartView: LineChartView!
@IBOutlet weak var pieChartView: PieChartView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
let unitsSold = [20.0, 4.0, 6.0, 3.0, 12.0, 16.0]
setChart(months, values: unitsSold)
}
func setChart(dataPoints: [String], values: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
let pieChartDataSet = PieChartDataSet(yVals: dataEntries, label: "Units Sold")
let pieChartData = PieChartData(xVals: dataPoints, dataSet: pieChartDataSet)
pieChartView.data = pieChartData
var colors: [UIColor] = []
for i in 0..<dataPoints.count {
let red = Double(arc4random_uniform(256))
let green = Double(arc4random_uniform(256))
let blue = Double(arc4random_uniform(256))
let color = UIColor(red: CGFloat(red/255), green: CGFloat(green/255), blue: CGFloat(blue/255), alpha: 1)
colors.append(color)
}
pieChartDataSet.colors = colors
let lineChartDataSet = LineChartDataSet(yVals: dataEntries, label: "Units Sold")
let lineChartData = LineChartData(xVals: dataPoints, dataSet: lineChartDataSet)
lineChartView.data = lineChartData
}
}
以上代码中,我们将 Charts 框架导入类中,像之前创建柱形图那样,创建一个饼状图和一个线形图。但需要注意的是,在柱形图表例中我们使用的是 BarChartDataEntry,而现在使用父类 ChartDataEntry 创建数据项。
运行应用,选择表格视图中的其他图表,可以看见一个线形图和有颜色的饼状图。你的应用可能跟下图不完全相同,因为饼状图的颜色是随机的。
结束语
本篇文章大致介绍了使用 ios-charts 库创建的一些图表类型,大概涉及了自定义图表的一些内容。如果你想知道这个库的其他功能,你可以参考这个下载库自带的 ChartsDemo 项目的代码,也可以看看该项目的维基百科。这个链接到 Wiki 页面会引导至 MPAndroidChart 项目文档。作者在写这篇文章时,还没有库的 iOS 版本的文档说明,但其实 API 跟 Android 版本约95%都相同,当你百思不得其解时,Android 文档仍然可以派上用场。
你可以在这里下载完整项目。
下面列出可创建的图表类型。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。