gif这是项目案例,需求是分别按照7天、30天、一年时间区分营收状况,下面结合Charts框架对需求进行分析解决。
Charts框架的Android版本是MPAndroidChart,两个框架代码相似度很高。
Charts开发本业务基本用到的类有:
BarChartView //长条柱类型的ChartView,继承于BarLineChartViewBase
xAxis //x轴坐标
leftAxis //y轴左边栏
rightAxis //y轴右边栏
legend //图标下面区分类型的显示
valueFormatter //显示值格式化,自定义Formatter每个轴都可以对value进行格式化
marker //点击条形柱显示出的marker气泡
BarChartData,BarChartDataSet,BarChartDataEntry //条形柱
他们之间的关系如图:
img
下面开始代码部分:
1、初始化BarChartView
chartView.delegate = self //设置代理
chartView.chartDescription?.enabled = false //表格内的描述label,禁用,设计图不需要此项
chartView.pinchZoomEnabled = false //手势缩放禁用
chartView.doubleTapToZoomEnabled = false //双击缩放禁用
chartView.scaleYEnabled = false //禁止Y轴扩大
chartView.scaleXEnabled = false //禁止X轴扩大
chartView.drawBarShadowEnabled = false //禁用Bar阴影
chartView.drawGridBackgroundEnabled = false // 禁用表格背景色
2、初始化xAxis
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom //文字显示在底部
xAxis.drawGridLinesEnabled = false //不显示x轴的表格线
xAxis.drawAxisLineEnabled = false //不显示x轴的线
xAxis.labelFont = UIFont.systemFont(ofSize: 10) //字体
xAxis.labelTextColor = UIColor.init(red: 0xa1/255, green: 0xa1/255, blue: 0xa1/255, alpha: 1) //颜色
xAxis.forceLabelsEnabled = false //禁用强制x轴的数量
3、初始化leftAxis
let leftAxis = chartView.leftAxis
leftAxis.drawAxisLineEnabled = false
leftAxis.gridLineDashLengths = [3, 3]//设置y轴的虚线
leftAxis.gridColor = UIColor.init(red: 0xe3/255, green: 0xe3/255, blue: 0xe3/255, alpha: 1)//虚线颜色
leftAxis.gridAntialiasEnabled = true//抗锯齿
leftAxis.labelCount = 3
leftAxis.forceLabelsEnabled = false
leftAxis.labelFont = UIFont.systemFont(ofSize: 10)
leftAxis.labelTextColor = UIColor.init(red: 0xa1/255, green: 0xa1/255, blue: 0xa1/255, alpha: 1)
4、其他初始化
chartView.rightAxis.enabled = false //禁用y轴的右边栏
chartView.legend.enabled = false//禁用表格下方描述
legend位置如图:
img
marker位置如图:
img
5、初始化BarChartData
// MARK: 图标更新数据
func updateChartData(_ count: Int, _ leftValues: [Int]) {
var yVals = [BarChartDataEntry]()
for i in 0 ..< count {
let bchart = BarChartDataEntry(x: Double(i), y: Double(leftValues[i]))
yVals.append(bchart)
}
var set1: BarChartDataSet? = nil
if chartView.data != nil && chartView.data!.dataSetCount > 0 {
set1 = chartView.data?.dataSets[0] as? BarChartDataSet
set1?.values = yVals
chartView.data?.notifyDataChanged()
chartView.notifyDataSetChanged()
}
else {
set1 = BarChartDataSet.init(values: yVals, label: nil)
set1?.drawValuesEnabled = false
set1?.highlightEnabled = false
set1?.colors = [UIColor.init(red: 0x69/255, green: 0x94/255, blue: 0xFC/255, alpha: 1)]
if let set = set1 {
let data = BarChartData.init(dataSets: [set])
chartView.data = data
}
}
chartView.animate(xAxisDuration: 1, yAxisDuration: 1, easingOption: .easeInOutSine)
}
初始化BarChartDataEntry数组yVals,根据count的遍历,生成x轴y轴的数据
var yVals = [BarChartDataEntry]()
for i in 0 ..< count {
let bchart = BarChartDataEntry(x: Double(i), y: Double(leftValues[i]))
yVals.append(bchart)
}
初始化BarChartDataSet,顾名思义,对给出的yVals数据进行点击、颜色等处理,然后赋给chartView进行刷新渲染
set1 = BarChartDataSet.init(values: yVals, label: nil) //
set1?.drawValuesEnabled = false //不显示条形柱上面value值
set1?.highlightEnabled = false //禁用点击条形柱,配合marker使用。
set1?.colors = [UIColor.init(red: 0x69/255, green: 0x94/255, blue: 0xFC/255, alpha: 1)]//条形柱的颜色
if let set = set1 {
let data = BarChartData.init(dataSets: [set])
chartView.data = data
}
动画显示条形柱数据
chartView.animate(xAxisDuration: 1, yAxisDuration: 1, easingOption: .easeInOutSine)
6、格式化X轴的值
7天、30天、一年,分别建立SevenDayValueFormatter、ThirtyDayValueFormatter、MonthDayValueFormatter三种类。
初始化SevenDayValueFormatter,遵守IAxisValueFormatter协议。
import UIKit
class SevenDayValueFormatter: NSObject, IAxisValueFormatter {
var sevenDays = [TimeInterval]()
override init() {
super.init()
let day7: TimeInterval = Date.timeIntervalSinceReferenceDate
for i in (1..<7).reversed() {
let day: TimeInterval = day7 - Double(24*60*60*i)
sevenDays.append(day)
}
sevenDays.append(day7)
}
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let idx: Int = Int(value)
if idx >= sevenDays.count {
return ""
}
let day = sevenDays[idx]
let date = Date.init(timeIntervalSinceReferenceDate: day)
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd"
let str = formatter.string(from: date)
return str
}
}
我们X轴的数据,会根据这个协议方法传过来,然后对x轴的数据处理,返回格式化后的数据。
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
}
初始化ThirtyDayValueFormatter,遵守IAxisValueFormatter协议。
import UIKit
class ThirtyDayValueFormatter: NSObject, IAxisValueFormatter {
var thirtyDays = [TimeInterval]()
override init() {
super.init()
let day30: TimeInterval = Date.timeIntervalSinceReferenceDate
for i in (1..<30).reversed() {
let day: TimeInterval = day30 - Double(24*60*60*i)
thirtyDays.append(day)
}
thirtyDays.append(day30)
}
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let idx: Int = Int(value)
if idx >= thirtyDays.count {
return ""
}
let day = thirtyDays[idx]
let date = Date.init(timeIntervalSinceReferenceDate: day)
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd"
let str = formatter.string(from: date)
return str
}
}
初始化MonthDayValueFormatter,遵守IAxisValueFormatter协议。
import UIKit
class MonthDayValueFormatter: NSObject, IAxisValueFormatter {
var monthDays = [TimeInterval]()
override init() {
super.init()
let compt = Calendar.current.dateComponents([.year, .month], from: Date())
let monthDayCurrent = Date.timeIntervalSinceReferenceDate
guard compt.year != nil else {return}
guard let month = compt.month else {return}
for i in (1..<12).reversed() {
let cmonth = month - i
var compt1 = DateComponents.init()
if cmonth <= 0 {
compt1.year = compt.year! - 1
compt1.month = 12 - abs(cmonth)
}
else {
compt1.year = compt.year
compt1.month = cmonth
}
let date = Calendar.current.date(from: compt1)
let monthDay = date!.timeIntervalSinceReferenceDate
monthDays.append(monthDay)
}
monthDays.append(monthDayCurrent)
}
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let idx: Int = Int(value)
if idx >= monthDays.count {
return ""
}
let day = monthDays[idx]
let date = Date.init(timeIntervalSinceReferenceDate: day)
let formatter = DateFormatter()
formatter.dateFormat = "yy/MM"
let str = formatter.string(from: date)
return str
}
}
7、刷新数据
获取x轴,赋值valueFormatter,更新chartView的data,适应屏幕fitScreen,根据内容数量设置缩放级别setScaleMinima。
func clickSegAction(_ tag: Int) {
let xAxis = chartView.xAxis
if tag == 0 {//7天
xAxis.valueFormatter = SevenDayValueFormatter()
updateChartData(7, [111,922,3,4,533,644,755,8,9,910,1111])
chartView.fitScreen()
chartView.setScaleMinima(1, scaleY: 1)
}
else if tag == 1 {//30天
xAxis.valueFormatter = ThirtyDayValueFormatter()
updateChartData(30, [111,922,3,4,533,644,755,8,9,910,1111,922,3,4,533,644,755,8,9,910,1111,922,3,4,533,644,755,8,9,910])
chartView.fitScreen()
chartView.setScaleMinima(3, scaleY: 1)
}
else if tag == 2 {//一年
xAxis.valueFormatter = MonthDayValueFormatter()
updateChartData(12, [111,922,3,4,533,644,755,8,9,910,1111,18])
chartView.fitScreen()
chartView.setScaleMinima(1.5, scaleY: 1)
}
}
总结
- 熟读Charts的Api接口,根据不同的接口尝试满足不同的需求。
- valueFormatter的设置主要看需求进行自定义。
- BarChartDataSet主要是对条形柱的各种处理,包括颜色、marker、虚线、渐变等,用处比较多。
- Charts库
关注我
欢迎关注公众号:jackyshan,技术干货首发微信,第一时间推送。