├── .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 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 3 | [![Twitter](https://img.shields.io/badge/twitter-@haojianzong.svg?style=flat)](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 --------------------------------------------------------------------------------