├── .gitignore
├── Package.swift
├── README.md
├── Sources
└── StackViewBarChart
│ ├── BarView.swift
│ ├── Helper
│ ├── LayoutUtility.swift
│ ├── UIColor+Helper.swift
│ └── UIColor+Percentage.swift
│ └── StackViewBarChart.swift
├── StackViewBarChart.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── StackViewBarChart.xcscheme
├── StackViewBarChartExample
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── SceneDelegate.swift
└── ViewController.swift
├── demo-gif.gif
├── demo-landscape.png
├── demo-portrait.png
└── intro.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 |
20 | # CocoaPods
21 | #
22 | # We recommend against adding the Pods directory to your .gitignore. However
23 | # you should judge for yourself, the pros and cons are mentioned at:
24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
25 | #
26 | # Pods/
27 |
28 | # Carthage
29 | #
30 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
31 | Carthage/Checkouts
32 | Carthage/Build
33 | .DS_Store
34 | *.dSYM.zip
35 |
36 | # fastlane
37 | screenshots
38 | fastlane/report.xml
39 | IdeaPod_mac.app
40 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "StackViewBarChart",
6 | platforms: [.iOS(.v13)],
7 | products: [.library(name: "StackViewBarChart", targets: ["StackViewBarChart"])],
8 | targets: [.target(name: "StackViewBarChart")]
9 | )
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # StackViewBarChart
2 | [](https://github.com/Carthage/Carthage)
3 | [](http://twitter.com/haojianzong)
4 |
5 |
6 |
7 | Create a simple bar chart with UIStackView, because...why not?
8 |
9 | UIStackView is my favorite AutoLayout tool now, so part of the project's goal is to explore UIStackView's capability. It turns out it is fairly easy to create a bar chart with UIStackView.
10 |
11 | ## Features
12 |
13 | - Customize chart legends
14 | - Implemented completely with UIStackView
15 | - Gradual bar color
16 | - Tiny code base (only 2 view classes)
17 | - Easy to folk and modify to use in your project
18 |
19 | ## Screenshots
20 |
21 |
22 |
23 |
24 | ## Requirements
25 |
26 | - iOS >= 12.0
27 | - Swift >= 5.0
28 |
29 | ## Usage
30 |
31 | ### Adding the StackViewBarChart to your project:
32 |
33 | There are two ways to add the ScrollableGraphView to your project.
34 |
35 | #### Manually
36 | Add all of the files in the [Classes](StackViewBarChartExample/Classes/) directory to your project in Xcode to your project in Xcode.
37 |
38 | #### Carthage
39 |
40 | Add to your Cartfile:
41 |
42 | ```
43 | github "haojianzong/StackViewBarChart" ~> 0.5.3
44 | ```
45 |
46 | Then make sure to link the frameworks and `import StackViewBarChart` in your code.
47 |
48 | #### CocoaPods
49 |
50 | CocoaPods is not supported
51 |
52 | ### Creating a bar chart with data.
53 |
54 | Create a StackViewBarChart instance then set its `numberList` property with custom data.
55 |
56 | ```swift
57 | class ViewController: UIViewController {
58 |
59 | // Initialize an instance
60 | let barChart = StackViewBarChart(frame: .zero)
61 |
62 | override func viewDidLoad() {
63 | super.viewDidLoad()
64 |
65 | // Setup its frame
66 | view.addSubview(barChart)
67 | barChart.frame = CGRect
68 | barChart.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
69 |
70 | // Set the data
71 | barChart.dataList = [
72 | .init(legend: "M", number: 0),
73 | .init(legend: "T", number: 2),
74 | .init(legend: "W", number: 7),
75 | .init(legend: "T", number: 8),
76 | .init(legend: "F", number: 30),
77 | .init(legend: "S", number: 20),
78 | .init(legend: "S", number: 10)
79 | }
80 | }
81 | ```
82 |
83 | ## Known Issues
84 |
85 | - Only support positive numbers
86 | - Autolayout warnings when there are too many bars and the frame is too small
87 |
88 | ## Other
89 |
90 | [Follow me on twitter](https://twitter.com/haojianzong) for interesting updates about other things that I make.
91 |
--------------------------------------------------------------------------------
/Sources/StackViewBarChart/BarView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarView.swift
3 | // StackViewBarChart
4 | //
5 | // Created by Jake on 10/12/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public class BarView: UIView {
13 |
14 | private struct Constants {
15 | static let numberFont = UIFont.systemFont(ofSize: 16.0, weight: .medium)
16 | static let legendFont = UIFont.systemFont(ofSize: 14.0, weight: .thin)
17 |
18 | static let itemSpacing: CGFloat = 5.0
19 | }
20 |
21 | public var containerHeight: CGFloat = 100.0 {
22 | didSet {
23 | updateBarHeight()
24 | }
25 | }
26 |
27 | public var barHeightConstant: CGFloat? {
28 | didSet {
29 | updateBarHeight()
30 | }
31 | }
32 |
33 | // The bar height percentage, doesn't contain the legend and number.
34 | public var barHeightPercentage: CGFloat? {
35 | didSet {
36 | updateBarHeight()
37 | }
38 | }
39 |
40 | let stackView: UIStackView
41 |
42 | public let bar = UIView()
43 | public let legendLabel = UILabel()
44 | public let numberLabel = UILabel()
45 |
46 | private let barHeightConstraint: NSLayoutConstraint
47 |
48 | // When both barHeightConstant and barHeightPercentage is set, prefer barHeightConstant
49 | private func updateBarHeight() {
50 |
51 | guard let barHeightPercentage = barHeightPercentage else {
52 | barHeightConstraint.constant = barHeightConstant ?? 0
53 | return
54 | }
55 |
56 | barHeightConstraint.constant = barMaxHeight * barHeightPercentage
57 | }
58 |
59 | private var barMaxHeight: CGFloat {
60 | return max(0, containerHeight - Constants.numberFont.lineHeight - Constants.legendFont.lineHeight - 2 * Constants.itemSpacing)
61 | }
62 |
63 | override init(frame: CGRect) {
64 | stackView = UIStackView(arrangedSubviews: [numberLabel, bar, legendLabel])
65 | stackView.axis = .vertical
66 | stackView.spacing = Constants.itemSpacing
67 |
68 | barHeightConstraint = bar.heightAnchor.constraint(equalToConstant: 0)
69 |
70 | super.init(frame: frame)
71 |
72 | bar.backgroundColor = .green
73 |
74 | addSubview(stackView)
75 | stackView.pinEdges(to: self)
76 |
77 | legendLabel.text = "n/a"
78 | legendLabel.textAlignment = .center
79 | legendLabel.font = Constants.legendFont
80 | legendLabel.textColor = UIColor(hex: 0xA9A8A9, alpha: 1.0)
81 |
82 | numberLabel.text = "0"
83 | numberLabel.textAlignment = .center
84 | numberLabel.font = Constants.numberFont
85 | numberLabel.textColor = UIColor(hex: 0x0D9275, alpha: 1.0)
86 |
87 | barHeightConstraint.isActive = true
88 | }
89 |
90 | override public func layoutSubviews() {
91 | super.layoutSubviews()
92 | updateBarHeight()
93 | }
94 |
95 | required init?(coder: NSCoder) { fatalError("not implemented") }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/Sources/StackViewBarChart/Helper/LayoutUtility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // layoutUtility.swift
3 | // zhiwoKit
4 | //
5 | // Created by Jake on 7/15/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | // MARK: - NSLayoutDimension shortcuts
13 | extension UIView {
14 |
15 | struct PinOptions: OptionSet {
16 |
17 | public let rawValue: Int
18 |
19 | public static let all: PinOptions = [.top, .trailing, .bottom, .leading]
20 |
21 | public static let top = PinOptions(rawValue: 1 << 0)
22 | public static let trailing = PinOptions(rawValue: 1 << 1)
23 | public static let bottom = PinOptions(rawValue: 1 << 2)
24 | public static let leading = PinOptions(rawValue: 1 << 3)
25 |
26 | public init(rawValue: Int) {
27 | self.rawValue = rawValue
28 | }
29 | }
30 |
31 | /// Add layout constraints. Also sets translatesAutoresizingMaskIntoConstraints to false.
32 | ///
33 | /// - Parameters:
34 | /// - parentView: parent view
35 | /// - edges: choose which edge to add
36 | func pinEdges(to parentView: UIView, edges: PinOptions = .all) {
37 |
38 | translatesAutoresizingMaskIntoConstraints = false
39 | if edges.contains(.leading) {
40 | leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true
41 | }
42 |
43 | if edges.contains(.trailing) {
44 | trailingAnchor.constraint(equalTo: parentView.trailingAnchor).isActive = true
45 | }
46 |
47 | if edges.contains(.top) {
48 | topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true
49 | }
50 |
51 | if edges.contains(.bottom) {
52 | bottomAnchor.constraint(equalTo:parentView.bottomAnchor).isActive = true
53 | }
54 | }
55 |
56 | /// Add layout constraints. Also sets translatesAutoresizingMaskIntoConstraints to false.
57 | ///
58 | /// - Parameters:
59 | /// - parentView: parent view
60 | /// - edges: choose which edge to add
61 | func pinMargins(to parentView: UIView, edges: PinOptions = .all) {
62 |
63 | translatesAutoresizingMaskIntoConstraints = false
64 | if edges.contains(.leading) {
65 | leadingAnchor.constraint(equalTo: parentView.layoutMarginsGuide.leadingAnchor).isActive = true
66 | }
67 |
68 | if edges.contains(.trailing) {
69 | trailingAnchor.constraint(equalTo: parentView.layoutMarginsGuide.trailingAnchor).isActive = true
70 | }
71 |
72 | if edges.contains(.top) {
73 | topAnchor.constraint(equalTo: parentView.layoutMarginsGuide.topAnchor).isActive = true
74 | }
75 |
76 | if edges.contains(.bottom) {
77 | bottomAnchor.constraint(equalTo:parentView.layoutMarginsGuide.bottomAnchor).isActive = true
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/Sources/StackViewBarChart/Helper/UIColor+Helper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Helper.swift
3 | // zhiwo
4 | //
5 | // Created by Jake on 8/13/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | extension UIColor {
13 |
14 | convenience init(hex: UInt32, alpha: CGFloat) {
15 | let red = CGFloat((hex & 0xFF0000) >> 16) / 255.0
16 | let green = CGFloat((hex & 0x00FF00) >> 8) / 255.0
17 | let blue = CGFloat((hex & 0x0000FF)) / 255.0
18 | self.init(red: red, green: green, blue: blue, alpha: alpha)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/StackViewBarChart/Helper/UIColor+Percentage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Percentage.swift
3 | // zhiwo
4 | //
5 | // Created by Jake on 8/11/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | extension UIColor {
13 |
14 | /// from a color to another color by percentage
15 | /// https://stackoverflow.com/a/46729248
16 | func toColor(_ color: UIColor, percentage: CGFloat) -> UIColor {
17 | let percentage = max(min(percentage, 1), 0)
18 | switch percentage {
19 | case 0: return self
20 | case 1: return color
21 | default:
22 | var (r1, g1, b1, a1): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
23 | var (r2, g2, b2, a2): (CGFloat, CGFloat, CGFloat, CGFloat) = (0, 0, 0, 0)
24 | guard self.getRed(&r1, green: &g1, blue: &b1, alpha: &a1) else { return self }
25 | guard color.getRed(&r2, green: &g2, blue: &b2, alpha: &a2) else { return self }
26 |
27 | return UIColor(red: CGFloat(r1 + (r2 - r1) * percentage),
28 | green: CGFloat(g1 + (g2 - g1) * percentage),
29 | blue: CGFloat(b1 + (b2 - b1) * percentage),
30 | alpha: CGFloat(a1 + (a2 - a1) * percentage))
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/StackViewBarChart/StackViewBarChart.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StackViewBarChart.swift
3 | // StackViewBarChart
4 | //
5 | // Created by Jake on 10/12/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public class StackViewBarChart: UIView {
13 |
14 | public struct Data {
15 | let legend: String
16 | let number: UInt
17 |
18 | public init(legend: String, number: UInt) {
19 | self.legend = legend
20 | self.number = number
21 | }
22 | }
23 |
24 | private struct Constants {
25 | static let fromColor = UIColor(hex: 0x0D9675, alpha: 1.0)
26 | static let toColor = UIColor(hex: 0x177087, alpha: 1.0)
27 |
28 | static let unitHeight: CGFloat = 15.0
29 | static let unitWidth: CGFloat = 20.0
30 | }
31 |
32 | public var dataList: [Data] = [
33 | Data(legend: "M", number: 0),
34 | Data(legend: "T", number: 0),
35 | Data(legend: "W", number: 0),
36 | Data(legend: "T", number: 0),
37 | Data(legend: "F", number: 0),
38 | Data(legend: "S", number: 0),
39 | Data(legend: "S", number: 0),
40 | ] {
41 | didSet {
42 | setNeedsLayout()
43 | }
44 | }
45 |
46 | var maxUnit: Int = 10
47 |
48 | let stackView: UIStackView
49 |
50 | override public init(frame: CGRect) {
51 | stackView = UIStackView()
52 | stackView.distribution = .equalSpacing
53 | stackView.translatesAutoresizingMaskIntoConstraints = false
54 | stackView.alignment = .bottom
55 | stackView.axis = .horizontal
56 |
57 | super.init(frame: frame)
58 |
59 | addSubview(stackView)
60 |
61 | stackView.pinEdges(to: self)
62 | }
63 |
64 | required init?(coder: NSCoder) { fatalError("not implemented") }
65 |
66 | func factoryViewList(containerHeight: CGFloat) -> [UIView] {
67 |
68 | let maxNumber = dataList.reduce(0) {
69 | return max($1.number, $0)
70 | }
71 |
72 | let shouldUseRelativeHeight = CGFloat(maxNumber) * Constants.unitHeight > (containerHeight / 2.0)
73 |
74 | var views = [UIView]()
75 | for (index, data) in dataList.enumerated() {
76 | let bar = BarView()
77 | bar.numberLabel.text = String(data.number)
78 | bar.legendLabel.text = data.legend
79 | bar.widthAnchor.constraint(equalToConstant: Constants.unitWidth).isActive = true
80 |
81 | bar.containerHeight = containerHeight
82 |
83 | if shouldUseRelativeHeight {
84 | // Each bar height is relative to the max bar height, while max bar height is 1.0
85 | bar.barHeightPercentage = CGFloat(data.number) / CGFloat(maxNumber)
86 | } else {
87 | // Prefers constant unit height when bar height is within half of container height
88 | bar.barHeightConstant = CGFloat(data.number) * Constants.unitHeight
89 | }
90 |
91 | bar.bar.backgroundColor = Constants.fromColor.toColor(Constants.toColor, percentage: CGFloat(index) / CGFloat(dataList.count))
92 | views.append(bar)
93 | }
94 |
95 | return views
96 | }
97 |
98 | override public func layoutSubviews() {
99 | super.layoutSubviews()
100 |
101 | stackView.arrangedSubviews.forEach {
102 | $0.removeFromSuperview()
103 | }
104 |
105 | for view in factoryViewList(containerHeight: frame.height) {
106 | stackView.addArrangedSubview(view)
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/StackViewBarChart.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 231CCC742352BEC700BC160D /* BarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 239A78452352050B001862E4 /* BarView.swift */; };
11 | 231CCC752352BEC700BC160D /* StackViewBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2303281F2351624800C116E5 /* StackViewBarChart.swift */; };
12 | 231CCC762352BECB00BC160D /* UIColor+Percentage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 239A78482352108C001862E4 /* UIColor+Percentage.swift */; };
13 | 231CCC772352BECB00BC160D /* UIColor+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 239A784A2352109A001862E4 /* UIColor+Helper.swift */; };
14 | 231CCC782352BECB00BC160D /* LayoutUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 238DE2A22352210800FDFB16 /* LayoutUtility.swift */; };
15 | 23317B7E2354B8A000DF6F96 /* UIColor+Percentage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 239A78482352108C001862E4 /* UIColor+Percentage.swift */; };
16 | 23317B7F2354B8A000DF6F96 /* UIColor+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 239A784A2352109A001862E4 /* UIColor+Helper.swift */; };
17 | 23317B802354B8A000DF6F96 /* LayoutUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 238DE2A22352210800FDFB16 /* LayoutUtility.swift */; };
18 | 23317B822354BD2200DF6F96 /* StackViewBarChart.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23388F8A2352BE8E007186C5 /* StackViewBarChart.framework */; };
19 | 23317B832354BD2200DF6F96 /* StackViewBarChart.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 23388F8A2352BE8E007186C5 /* StackViewBarChart.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
20 | 23515BA52353060B00CB95CA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23515BA42353060B00CB95CA /* AppDelegate.swift */; };
21 | 23515BA72353060B00CB95CA /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23515BA62353060B00CB95CA /* SceneDelegate.swift */; };
22 | 23515BA92353060B00CB95CA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23515BA82353060B00CB95CA /* ViewController.swift */; };
23 | 23515BAC2353060B00CB95CA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 23515BAA2353060B00CB95CA /* Main.storyboard */; };
24 | 23515BAE2353060B00CB95CA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 23515BAD2353060B00CB95CA /* Assets.xcassets */; };
25 | 23515BB12353060B00CB95CA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 23515BAF2353060B00CB95CA /* LaunchScreen.storyboard */; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXContainerItemProxy section */
29 | 23317B842354BD2200DF6F96 /* PBXContainerItemProxy */ = {
30 | isa = PBXContainerItemProxy;
31 | containerPortal = 230328002351623800C116E5 /* Project object */;
32 | proxyType = 1;
33 | remoteGlobalIDString = 23388F892352BE8E007186C5;
34 | remoteInfo = StackViewBarChart;
35 | };
36 | /* End PBXContainerItemProxy section */
37 |
38 | /* Begin PBXCopyFilesBuildPhase section */
39 | 23317B862354BD2200DF6F96 /* Embed Frameworks */ = {
40 | isa = PBXCopyFilesBuildPhase;
41 | buildActionMask = 2147483647;
42 | dstPath = "";
43 | dstSubfolderSpec = 10;
44 | files = (
45 | 23317B832354BD2200DF6F96 /* StackViewBarChart.framework in Embed Frameworks */,
46 | );
47 | name = "Embed Frameworks";
48 | runOnlyForDeploymentPostprocessing = 0;
49 | };
50 | /* End PBXCopyFilesBuildPhase section */
51 |
52 | /* Begin PBXFileReference section */
53 | 2303281F2351624800C116E5 /* StackViewBarChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackViewBarChart.swift; sourceTree = ""; };
54 | 23388F8A2352BE8E007186C5 /* StackViewBarChart.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StackViewBarChart.framework; sourceTree = BUILT_PRODUCTS_DIR; };
55 | 23515BA22353060B00CB95CA /* StackViewBarChartExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StackViewBarChartExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
56 | 23515BA42353060B00CB95CA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
57 | 23515BA62353060B00CB95CA /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
58 | 23515BA82353060B00CB95CA /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
59 | 23515BAB2353060B00CB95CA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
60 | 23515BAD2353060B00CB95CA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
61 | 23515BB02353060B00CB95CA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
62 | 23515BB22353060B00CB95CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | 238DE2A22352210800FDFB16 /* LayoutUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutUtility.swift; sourceTree = ""; };
64 | 239A78452352050B001862E4 /* BarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarView.swift; sourceTree = ""; };
65 | 239A78482352108C001862E4 /* UIColor+Percentage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Percentage.swift"; sourceTree = ""; };
66 | 239A784A2352109A001862E4 /* UIColor+Helper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Helper.swift"; sourceTree = ""; };
67 | /* End PBXFileReference section */
68 |
69 | /* Begin PBXFrameworksBuildPhase section */
70 | 23388F872352BE8E007186C5 /* Frameworks */ = {
71 | isa = PBXFrameworksBuildPhase;
72 | buildActionMask = 2147483647;
73 | files = (
74 | );
75 | runOnlyForDeploymentPostprocessing = 0;
76 | };
77 | 23515B9F2353060B00CB95CA /* Frameworks */ = {
78 | isa = PBXFrameworksBuildPhase;
79 | buildActionMask = 2147483647;
80 | files = (
81 | 23317B822354BD2200DF6F96 /* StackViewBarChart.framework in Frameworks */,
82 | );
83 | runOnlyForDeploymentPostprocessing = 0;
84 | };
85 | /* End PBXFrameworksBuildPhase section */
86 |
87 | /* Begin PBXGroup section */
88 | 230327FF2351623800C116E5 = {
89 | isa = PBXGroup;
90 | children = (
91 | 231CCC732352BEB800BC160D /* Sources */,
92 | 23515BA32353060B00CB95CA /* StackViewBarChartExample */,
93 | 230328092351623800C116E5 /* Products */,
94 | 23317B812354BD2200DF6F96 /* Frameworks */,
95 | );
96 | sourceTree = "";
97 | };
98 | 230328092351623800C116E5 /* Products */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 23388F8A2352BE8E007186C5 /* StackViewBarChart.framework */,
102 | 23515BA22353060B00CB95CA /* StackViewBarChartExample.app */,
103 | );
104 | name = Products;
105 | sourceTree = "";
106 | };
107 | 231CCC732352BEB800BC160D /* Sources */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 2349A02226B6A145006E74C4 /* StackViewBarChart */,
111 | );
112 | path = Sources;
113 | sourceTree = "";
114 | };
115 | 23317B812354BD2200DF6F96 /* Frameworks */ = {
116 | isa = PBXGroup;
117 | children = (
118 | );
119 | name = Frameworks;
120 | sourceTree = "";
121 | };
122 | 2349A02226B6A145006E74C4 /* StackViewBarChart */ = {
123 | isa = PBXGroup;
124 | children = (
125 | 239A784723521080001862E4 /* Helper */,
126 | 239A78452352050B001862E4 /* BarView.swift */,
127 | 2303281F2351624800C116E5 /* StackViewBarChart.swift */,
128 | );
129 | path = StackViewBarChart;
130 | sourceTree = "";
131 | };
132 | 23515BA32353060B00CB95CA /* StackViewBarChartExample */ = {
133 | isa = PBXGroup;
134 | children = (
135 | 23515BA42353060B00CB95CA /* AppDelegate.swift */,
136 | 23515BA62353060B00CB95CA /* SceneDelegate.swift */,
137 | 23515BA82353060B00CB95CA /* ViewController.swift */,
138 | 23515BAA2353060B00CB95CA /* Main.storyboard */,
139 | 23515BAD2353060B00CB95CA /* Assets.xcassets */,
140 | 23515BAF2353060B00CB95CA /* LaunchScreen.storyboard */,
141 | 23515BB22353060B00CB95CA /* Info.plist */,
142 | );
143 | path = StackViewBarChartExample;
144 | sourceTree = "";
145 | };
146 | 239A784723521080001862E4 /* Helper */ = {
147 | isa = PBXGroup;
148 | children = (
149 | 239A78482352108C001862E4 /* UIColor+Percentage.swift */,
150 | 239A784A2352109A001862E4 /* UIColor+Helper.swift */,
151 | 238DE2A22352210800FDFB16 /* LayoutUtility.swift */,
152 | );
153 | path = Helper;
154 | sourceTree = "";
155 | };
156 | /* End PBXGroup section */
157 |
158 | /* Begin PBXHeadersBuildPhase section */
159 | 23388F852352BE8E007186C5 /* Headers */ = {
160 | isa = PBXHeadersBuildPhase;
161 | buildActionMask = 2147483647;
162 | files = (
163 | );
164 | runOnlyForDeploymentPostprocessing = 0;
165 | };
166 | /* End PBXHeadersBuildPhase section */
167 |
168 | /* Begin PBXNativeTarget section */
169 | 23388F892352BE8E007186C5 /* StackViewBarChart */ = {
170 | isa = PBXNativeTarget;
171 | buildConfigurationList = 23388F962352BE8E007186C5 /* Build configuration list for PBXNativeTarget "StackViewBarChart" */;
172 | buildPhases = (
173 | 23388F852352BE8E007186C5 /* Headers */,
174 | 23388F862352BE8E007186C5 /* Sources */,
175 | 23388F872352BE8E007186C5 /* Frameworks */,
176 | 23388F882352BE8E007186C5 /* Resources */,
177 | );
178 | buildRules = (
179 | );
180 | dependencies = (
181 | );
182 | name = StackViewBarChart;
183 | productName = StackViewBarChartKit;
184 | productReference = 23388F8A2352BE8E007186C5 /* StackViewBarChart.framework */;
185 | productType = "com.apple.product-type.framework";
186 | };
187 | 23515BA12353060B00CB95CA /* StackViewBarChartExample */ = {
188 | isa = PBXNativeTarget;
189 | buildConfigurationList = 23515BB32353060B00CB95CA /* Build configuration list for PBXNativeTarget "StackViewBarChartExample" */;
190 | buildPhases = (
191 | 23515B9E2353060B00CB95CA /* Sources */,
192 | 23515B9F2353060B00CB95CA /* Frameworks */,
193 | 23515BA02353060B00CB95CA /* Resources */,
194 | 23317B862354BD2200DF6F96 /* Embed Frameworks */,
195 | );
196 | buildRules = (
197 | );
198 | dependencies = (
199 | 23317B852354BD2200DF6F96 /* PBXTargetDependency */,
200 | );
201 | name = StackViewBarChartExample;
202 | productName = StackViewBarChartExample;
203 | productReference = 23515BA22353060B00CB95CA /* StackViewBarChartExample.app */;
204 | productType = "com.apple.product-type.application";
205 | };
206 | /* End PBXNativeTarget section */
207 |
208 | /* Begin PBXProject section */
209 | 230328002351623800C116E5 /* Project object */ = {
210 | isa = PBXProject;
211 | attributes = {
212 | LastSwiftUpdateCheck = 1100;
213 | LastUpgradeCheck = 1100;
214 | ORGANIZATIONNAME = Jake;
215 | TargetAttributes = {
216 | 23388F892352BE8E007186C5 = {
217 | CreatedOnToolsVersion = 11.0;
218 | };
219 | 23515BA12353060B00CB95CA = {
220 | CreatedOnToolsVersion = 11.0;
221 | };
222 | };
223 | };
224 | buildConfigurationList = 230328032351623800C116E5 /* Build configuration list for PBXProject "StackViewBarChart" */;
225 | compatibilityVersion = "Xcode 9.3";
226 | developmentRegion = en;
227 | hasScannedForEncodings = 0;
228 | knownRegions = (
229 | en,
230 | Base,
231 | );
232 | mainGroup = 230327FF2351623800C116E5;
233 | productRefGroup = 230328092351623800C116E5 /* Products */;
234 | projectDirPath = "";
235 | projectRoot = "";
236 | targets = (
237 | 23388F892352BE8E007186C5 /* StackViewBarChart */,
238 | 23515BA12353060B00CB95CA /* StackViewBarChartExample */,
239 | );
240 | };
241 | /* End PBXProject section */
242 |
243 | /* Begin PBXResourcesBuildPhase section */
244 | 23388F882352BE8E007186C5 /* Resources */ = {
245 | isa = PBXResourcesBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | );
249 | runOnlyForDeploymentPostprocessing = 0;
250 | };
251 | 23515BA02353060B00CB95CA /* Resources */ = {
252 | isa = PBXResourcesBuildPhase;
253 | buildActionMask = 2147483647;
254 | files = (
255 | 23515BB12353060B00CB95CA /* LaunchScreen.storyboard in Resources */,
256 | 23515BAE2353060B00CB95CA /* Assets.xcassets in Resources */,
257 | 23515BAC2353060B00CB95CA /* Main.storyboard in Resources */,
258 | );
259 | runOnlyForDeploymentPostprocessing = 0;
260 | };
261 | /* End PBXResourcesBuildPhase section */
262 |
263 | /* Begin PBXSourcesBuildPhase section */
264 | 23388F862352BE8E007186C5 /* Sources */ = {
265 | isa = PBXSourcesBuildPhase;
266 | buildActionMask = 2147483647;
267 | files = (
268 | 231CCC782352BECB00BC160D /* LayoutUtility.swift in Sources */,
269 | 231CCC762352BECB00BC160D /* UIColor+Percentage.swift in Sources */,
270 | 231CCC752352BEC700BC160D /* StackViewBarChart.swift in Sources */,
271 | 231CCC742352BEC700BC160D /* BarView.swift in Sources */,
272 | 231CCC772352BECB00BC160D /* UIColor+Helper.swift in Sources */,
273 | );
274 | runOnlyForDeploymentPostprocessing = 0;
275 | };
276 | 23515B9E2353060B00CB95CA /* Sources */ = {
277 | isa = PBXSourcesBuildPhase;
278 | buildActionMask = 2147483647;
279 | files = (
280 | 23515BA92353060B00CB95CA /* ViewController.swift in Sources */,
281 | 23317B7E2354B8A000DF6F96 /* UIColor+Percentage.swift in Sources */,
282 | 23317B802354B8A000DF6F96 /* LayoutUtility.swift in Sources */,
283 | 23515BA52353060B00CB95CA /* AppDelegate.swift in Sources */,
284 | 23317B7F2354B8A000DF6F96 /* UIColor+Helper.swift in Sources */,
285 | 23515BA72353060B00CB95CA /* SceneDelegate.swift in Sources */,
286 | );
287 | runOnlyForDeploymentPostprocessing = 0;
288 | };
289 | /* End PBXSourcesBuildPhase section */
290 |
291 | /* Begin PBXTargetDependency section */
292 | 23317B852354BD2200DF6F96 /* PBXTargetDependency */ = {
293 | isa = PBXTargetDependency;
294 | target = 23388F892352BE8E007186C5 /* StackViewBarChart */;
295 | targetProxy = 23317B842354BD2200DF6F96 /* PBXContainerItemProxy */;
296 | };
297 | /* End PBXTargetDependency section */
298 |
299 | /* Begin PBXVariantGroup section */
300 | 23515BAA2353060B00CB95CA /* Main.storyboard */ = {
301 | isa = PBXVariantGroup;
302 | children = (
303 | 23515BAB2353060B00CB95CA /* Base */,
304 | );
305 | name = Main.storyboard;
306 | sourceTree = "";
307 | };
308 | 23515BAF2353060B00CB95CA /* LaunchScreen.storyboard */ = {
309 | isa = PBXVariantGroup;
310 | children = (
311 | 23515BB02353060B00CB95CA /* Base */,
312 | );
313 | name = LaunchScreen.storyboard;
314 | sourceTree = "";
315 | };
316 | /* End PBXVariantGroup section */
317 |
318 | /* Begin XCBuildConfiguration section */
319 | 2303281A2351623A00C116E5 /* Debug */ = {
320 | isa = XCBuildConfiguration;
321 | buildSettings = {
322 | ALWAYS_SEARCH_USER_PATHS = NO;
323 | CLANG_ANALYZER_NONNULL = YES;
324 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
326 | CLANG_CXX_LIBRARY = "libc++";
327 | CLANG_ENABLE_MODULES = YES;
328 | CLANG_ENABLE_OBJC_ARC = YES;
329 | CLANG_ENABLE_OBJC_WEAK = YES;
330 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
331 | CLANG_WARN_BOOL_CONVERSION = YES;
332 | CLANG_WARN_COMMA = YES;
333 | CLANG_WARN_CONSTANT_CONVERSION = YES;
334 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
335 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
336 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
337 | CLANG_WARN_EMPTY_BODY = YES;
338 | CLANG_WARN_ENUM_CONVERSION = YES;
339 | CLANG_WARN_INFINITE_RECURSION = YES;
340 | CLANG_WARN_INT_CONVERSION = YES;
341 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
342 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
343 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
344 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
345 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
346 | CLANG_WARN_STRICT_PROTOTYPES = YES;
347 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
348 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
349 | CLANG_WARN_UNREACHABLE_CODE = YES;
350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
351 | COPY_PHASE_STRIP = NO;
352 | DEBUG_INFORMATION_FORMAT = dwarf;
353 | ENABLE_STRICT_OBJC_MSGSEND = YES;
354 | ENABLE_TESTABILITY = YES;
355 | GCC_C_LANGUAGE_STANDARD = gnu11;
356 | GCC_DYNAMIC_NO_PIC = NO;
357 | GCC_NO_COMMON_BLOCKS = YES;
358 | GCC_OPTIMIZATION_LEVEL = 0;
359 | GCC_PREPROCESSOR_DEFINITIONS = (
360 | "DEBUG=1",
361 | "$(inherited)",
362 | );
363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
365 | GCC_WARN_UNDECLARED_SELECTOR = YES;
366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
367 | GCC_WARN_UNUSED_FUNCTION = YES;
368 | GCC_WARN_UNUSED_VARIABLE = YES;
369 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
370 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
371 | MTL_FAST_MATH = YES;
372 | ONLY_ACTIVE_ARCH = YES;
373 | SDKROOT = iphoneos;
374 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
375 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
376 | };
377 | name = Debug;
378 | };
379 | 2303281B2351623A00C116E5 /* Release */ = {
380 | isa = XCBuildConfiguration;
381 | buildSettings = {
382 | ALWAYS_SEARCH_USER_PATHS = NO;
383 | CLANG_ANALYZER_NONNULL = YES;
384 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
385 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
386 | CLANG_CXX_LIBRARY = "libc++";
387 | CLANG_ENABLE_MODULES = YES;
388 | CLANG_ENABLE_OBJC_ARC = YES;
389 | CLANG_ENABLE_OBJC_WEAK = YES;
390 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
391 | CLANG_WARN_BOOL_CONVERSION = YES;
392 | CLANG_WARN_COMMA = YES;
393 | CLANG_WARN_CONSTANT_CONVERSION = YES;
394 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
395 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
396 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
397 | CLANG_WARN_EMPTY_BODY = YES;
398 | CLANG_WARN_ENUM_CONVERSION = YES;
399 | CLANG_WARN_INFINITE_RECURSION = YES;
400 | CLANG_WARN_INT_CONVERSION = YES;
401 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
402 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
403 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
404 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
405 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
406 | CLANG_WARN_STRICT_PROTOTYPES = YES;
407 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
408 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
409 | CLANG_WARN_UNREACHABLE_CODE = YES;
410 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
411 | COPY_PHASE_STRIP = NO;
412 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
413 | ENABLE_NS_ASSERTIONS = NO;
414 | ENABLE_STRICT_OBJC_MSGSEND = YES;
415 | GCC_C_LANGUAGE_STANDARD = gnu11;
416 | GCC_NO_COMMON_BLOCKS = YES;
417 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
418 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
419 | GCC_WARN_UNDECLARED_SELECTOR = YES;
420 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
421 | GCC_WARN_UNUSED_FUNCTION = YES;
422 | GCC_WARN_UNUSED_VARIABLE = YES;
423 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
424 | MTL_ENABLE_DEBUG_INFO = NO;
425 | MTL_FAST_MATH = YES;
426 | SDKROOT = iphoneos;
427 | SWIFT_COMPILATION_MODE = wholemodule;
428 | SWIFT_OPTIMIZATION_LEVEL = "-O";
429 | VALIDATE_PRODUCT = YES;
430 | };
431 | name = Release;
432 | };
433 | 23388F942352BE8E007186C5 /* Debug */ = {
434 | isa = XCBuildConfiguration;
435 | buildSettings = {
436 | CODE_SIGN_STYLE = Automatic;
437 | CURRENT_PROJECT_VERSION = 1;
438 | DEFINES_MODULE = YES;
439 | DEVELOPMENT_TEAM = L74SB6D87X;
440 | DYLIB_COMPATIBILITY_VERSION = 1;
441 | DYLIB_CURRENT_VERSION = 1;
442 | DYLIB_INSTALL_NAME_BASE = "@rpath";
443 | INFOPLIST_FILE = StackViewBarChartExample/Info.plist;
444 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
445 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
446 | LD_RUNPATH_SEARCH_PATHS = (
447 | "$(inherited)",
448 | "@executable_path/Frameworks",
449 | "@loader_path/Frameworks",
450 | );
451 | MARKETING_VERSION = 0.5.6;
452 | PRODUCT_BUNDLE_IDENTIFIER = com.jakehao.ios.StackViewBarChartKit;
453 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
454 | SKIP_INSTALL = YES;
455 | SWIFT_VERSION = 5.0;
456 | TARGETED_DEVICE_FAMILY = "1,2";
457 | VERSIONING_SYSTEM = "apple-generic";
458 | VERSION_INFO_PREFIX = "";
459 | };
460 | name = Debug;
461 | };
462 | 23388F952352BE8E007186C5 /* Release */ = {
463 | isa = XCBuildConfiguration;
464 | buildSettings = {
465 | CODE_SIGN_STYLE = Automatic;
466 | CURRENT_PROJECT_VERSION = 1;
467 | DEFINES_MODULE = YES;
468 | DEVELOPMENT_TEAM = L74SB6D87X;
469 | DYLIB_COMPATIBILITY_VERSION = 1;
470 | DYLIB_CURRENT_VERSION = 1;
471 | DYLIB_INSTALL_NAME_BASE = "@rpath";
472 | INFOPLIST_FILE = StackViewBarChartExample/Info.plist;
473 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
474 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
475 | LD_RUNPATH_SEARCH_PATHS = (
476 | "$(inherited)",
477 | "@executable_path/Frameworks",
478 | "@loader_path/Frameworks",
479 | );
480 | MARKETING_VERSION = 0.5.6;
481 | PRODUCT_BUNDLE_IDENTIFIER = com.jakehao.ios.StackViewBarChartKit;
482 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
483 | SKIP_INSTALL = YES;
484 | SWIFT_VERSION = 5.0;
485 | TARGETED_DEVICE_FAMILY = "1,2";
486 | VERSIONING_SYSTEM = "apple-generic";
487 | VERSION_INFO_PREFIX = "";
488 | };
489 | name = Release;
490 | };
491 | 23515BB42353060B00CB95CA /* Debug */ = {
492 | isa = XCBuildConfiguration;
493 | buildSettings = {
494 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
495 | CODE_SIGN_STYLE = Automatic;
496 | DEVELOPMENT_TEAM = L74SB6D87X;
497 | INFOPLIST_FILE = StackViewBarChartExample/Info.plist;
498 | LD_RUNPATH_SEARCH_PATHS = (
499 | "$(inherited)",
500 | "@executable_path/Frameworks",
501 | );
502 | MARKETING_VERSION = 0.5.6;
503 | PRODUCT_BUNDLE_IDENTIFIER = com.jakehao.ios.StackViewBarChartExample;
504 | PRODUCT_NAME = "$(TARGET_NAME)";
505 | SWIFT_VERSION = 5.0;
506 | TARGETED_DEVICE_FAMILY = "1,2";
507 | };
508 | name = Debug;
509 | };
510 | 23515BB52353060B00CB95CA /* Release */ = {
511 | isa = XCBuildConfiguration;
512 | buildSettings = {
513 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
514 | CODE_SIGN_STYLE = Automatic;
515 | DEVELOPMENT_TEAM = L74SB6D87X;
516 | INFOPLIST_FILE = StackViewBarChartExample/Info.plist;
517 | LD_RUNPATH_SEARCH_PATHS = (
518 | "$(inherited)",
519 | "@executable_path/Frameworks",
520 | );
521 | MARKETING_VERSION = 0.5.6;
522 | PRODUCT_BUNDLE_IDENTIFIER = com.jakehao.ios.StackViewBarChartExample;
523 | PRODUCT_NAME = "$(TARGET_NAME)";
524 | SWIFT_VERSION = 5.0;
525 | TARGETED_DEVICE_FAMILY = "1,2";
526 | };
527 | name = Release;
528 | };
529 | /* End XCBuildConfiguration section */
530 |
531 | /* Begin XCConfigurationList section */
532 | 230328032351623800C116E5 /* Build configuration list for PBXProject "StackViewBarChart" */ = {
533 | isa = XCConfigurationList;
534 | buildConfigurations = (
535 | 2303281A2351623A00C116E5 /* Debug */,
536 | 2303281B2351623A00C116E5 /* Release */,
537 | );
538 | defaultConfigurationIsVisible = 0;
539 | defaultConfigurationName = Release;
540 | };
541 | 23388F962352BE8E007186C5 /* Build configuration list for PBXNativeTarget "StackViewBarChart" */ = {
542 | isa = XCConfigurationList;
543 | buildConfigurations = (
544 | 23388F942352BE8E007186C5 /* Debug */,
545 | 23388F952352BE8E007186C5 /* Release */,
546 | );
547 | defaultConfigurationIsVisible = 0;
548 | defaultConfigurationName = Release;
549 | };
550 | 23515BB32353060B00CB95CA /* Build configuration list for PBXNativeTarget "StackViewBarChartExample" */ = {
551 | isa = XCConfigurationList;
552 | buildConfigurations = (
553 | 23515BB42353060B00CB95CA /* Debug */,
554 | 23515BB52353060B00CB95CA /* Release */,
555 | );
556 | defaultConfigurationIsVisible = 0;
557 | defaultConfigurationName = Release;
558 | };
559 | /* End XCConfigurationList section */
560 | };
561 | rootObject = 230328002351623800C116E5 /* Project object */;
562 | }
563 |
--------------------------------------------------------------------------------
/StackViewBarChart.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/StackViewBarChart.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/StackViewBarChart.xcodeproj/xcshareddata/xcschemes/StackViewBarChart.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/StackViewBarChartExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // StackViewBarChartExample
4 | //
5 | // Created by Jake on 10/13/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/StackViewBarChartExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/StackViewBarChartExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/StackViewBarChartExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/StackViewBarChartExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/StackViewBarChartExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | $(MARKETING_VERSION)
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/StackViewBarChartExample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // StackViewBarChartExample
4 | //
5 | // Created by Jake on 10/13/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 | guard let _ = (scene as? UIWindowScene) else { return }
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/StackViewBarChartExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // StackViewBarChart
4 | //
5 | // Created by Jake on 10/12/19.
6 | // Copyright © 2019 Jake. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import StackViewBarChart
11 |
12 | class ViewController: UIViewController {
13 |
14 | private struct Constants {
15 | static let chartHeight: CGFloat = 300.0
16 | static let margin: CGFloat = 10.0
17 | }
18 |
19 | let barChart = StackViewBarChart(frame: .zero)
20 |
21 | let reloadButton = UIButton(type: .system)
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 | // Do any additional setup after loading the view.
26 |
27 | let stackView = UIStackView(arrangedSubviews: [barChart, reloadButton])
28 | stackView.axis = .vertical
29 |
30 | reloadButton.setTitle("Reload data", for: .normal)
31 | reloadButton.addTarget(self, action: #selector(reload), for: .touchUpInside)
32 |
33 | view.addSubview(stackView)
34 | stackView.pinMargins(to: view)
35 |
36 | NSLayoutConstraint.activate([
37 | barChart.heightAnchor.constraint(equalToConstant: Constants.chartHeight),
38 | ])
39 |
40 | view.backgroundColor = UIColor(hex: 0x0f214a, alpha: 1.0)
41 | reload()
42 | }
43 |
44 | @objc private func reload() {
45 | self.barChart.dataList = [
46 | .init(legend: "M", number: UInt.random(in: 0...10)),
47 | .init(legend: "T", number: UInt.random(in: 0...10)),
48 | .init(legend: "W", number: UInt.random(in: 0...10)),
49 | .init(legend: "T", number: UInt.random(in: 0...10)),
50 | .init(legend: "F", number: UInt.random(in: 0...10)),
51 | .init(legend: "S", number: UInt.random(in: 0...10)),
52 | .init(legend: "S", number: UInt.random(in: 0...10))
53 | ]
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/demo-gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haojianzong/StackViewBarChart/d82e8f79f3240ce6552f4b4d3042c5c1f8d7f6bb/demo-gif.gif
--------------------------------------------------------------------------------
/demo-landscape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haojianzong/StackViewBarChart/d82e8f79f3240ce6552f4b4d3042c5c1f8d7f6bb/demo-landscape.png
--------------------------------------------------------------------------------
/demo-portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haojianzong/StackViewBarChart/d82e8f79f3240ce6552f4b4d3042c5c1f8d7f6bb/demo-portrait.png
--------------------------------------------------------------------------------
/intro.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/haojianzong/StackViewBarChart/d82e8f79f3240ce6552f4b4d3042c5c1f8d7f6bb/intro.jpg
--------------------------------------------------------------------------------