From f9c4bd57aff63f89ca67440b1b689594d8ed9c1f Mon Sep 17 00:00:00 2001 From: Antonin Biret Date: Sun, 31 Jul 2016 22:15:32 +0200 Subject: [PATCH 1/2] Added UIStackView in storyboard exemple --- .../Exemple.xcodeproj/project.pbxproj | 6 ++ .../AppIcon.appiconset/Contents.json | 5 ++ .../Exemple/Base.lproj/Main.storyboard | 79 +++++++++++-------- .../Exemple/ExempleViewController.swift | 3 + Exemple-ABSteppedProgressBar/Podfile.lock | 4 +- .../ABSteppedProgressBar.podspec.json | 4 +- .../Pods/Manifest.lock | 4 +- .../xcschemes/xcschememanagement.plist | 10 --- .../ABSteppedProgressBar/Info.plist | 2 +- 9 files changed, 66 insertions(+), 51 deletions(-) diff --git a/Exemple-ABSteppedProgressBar/Exemple.xcodeproj/project.pbxproj b/Exemple-ABSteppedProgressBar/Exemple.xcodeproj/project.pbxproj index fd9566d..650a82c 100644 --- a/Exemple-ABSteppedProgressBar/Exemple.xcodeproj/project.pbxproj +++ b/Exemple-ABSteppedProgressBar/Exemple.xcodeproj/project.pbxproj @@ -327,10 +327,13 @@ baseConfigurationReference = 2D13ABDFC150D98A2F44B2DE /* Pods-Exemple.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEAD_CODE_STRIPPING = NO; INFOPLIST_FILE = Exemple/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = fr.antoninbiret.Exemple; PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + STRIP_STYLE = debugging; }; name = Debug; }; @@ -339,10 +342,13 @@ baseConfigurationReference = 65649D4FA8E5DD4AEC2EF0F9 /* Pods-Exemple.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEAD_CODE_STRIPPING = NO; INFOPLIST_FILE = Exemple/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = fr.antoninbiret.Exemple; PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + STRIP_STYLE = debugging; }; name = Release; }; diff --git a/Exemple-ABSteppedProgressBar/Exemple/Assets.xcassets/AppIcon.appiconset/Contents.json b/Exemple-ABSteppedProgressBar/Exemple/Assets.xcassets/AppIcon.appiconset/Contents.json index 36d2c80..eeea76c 100644 --- a/Exemple-ABSteppedProgressBar/Exemple/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Exemple-ABSteppedProgressBar/Exemple/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -59,6 +59,11 @@ "idiom" : "ipad", "size" : "76x76", "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" } ], "info" : { diff --git a/Exemple-ABSteppedProgressBar/Exemple/Base.lproj/Main.storyboard b/Exemple-ABSteppedProgressBar/Exemple/Base.lproj/Main.storyboard index 4eac7c5..5719335 100644 --- a/Exemple-ABSteppedProgressBar/Exemple/Base.lproj/Main.storyboard +++ b/Exemple-ABSteppedProgressBar/Exemple/Base.lproj/Main.storyboard @@ -3,6 +3,7 @@ + @@ -87,43 +88,53 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + diff --git a/Exemple-ABSteppedProgressBar/Exemple/ExempleViewController.swift b/Exemple-ABSteppedProgressBar/Exemple/ExempleViewController.swift index 9e7e187..783557c 100644 --- a/Exemple-ABSteppedProgressBar/Exemple/ExempleViewController.swift +++ b/Exemple-ABSteppedProgressBar/Exemple/ExempleViewController.swift @@ -34,6 +34,9 @@ class ExempleViewController: UIViewController { progressBar.progressLineHeight = 10 progressBar.delegate = self + + progressBar.backgroundShapeColor = UIColor(red: 231/255, green: 231/255, blue: 231/255, alpha: 1) + progressBar.selectedBackgoundColor = UIColor(red: 64/255, green: 173/255, blue: 21/255, alpha: 1) } } diff --git a/Exemple-ABSteppedProgressBar/Podfile.lock b/Exemple-ABSteppedProgressBar/Podfile.lock index b3d85fb..65c6a16 100644 --- a/Exemple-ABSteppedProgressBar/Podfile.lock +++ b/Exemple-ABSteppedProgressBar/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - ABSteppedProgressBar (0.0.3) + - ABSteppedProgressBar (0.0.4) DEPENDENCIES: - ABSteppedProgressBar (from `../`) @@ -9,7 +9,7 @@ EXTERNAL SOURCES: :path: ../ SPEC CHECKSUMS: - ABSteppedProgressBar: 2f4f51ad45a9610f15fb696e2447482e690210c5 + ABSteppedProgressBar: 931e2f628e425cd3491a1db6efc59c12ff991981 PODFILE CHECKSUM: 6a8e347d3f7d25053b7843d2d2f4b942079e6494 diff --git a/Exemple-ABSteppedProgressBar/Pods/Local Podspecs/ABSteppedProgressBar.podspec.json b/Exemple-ABSteppedProgressBar/Pods/Local Podspecs/ABSteppedProgressBar.podspec.json index 1fc322b..557b336 100644 --- a/Exemple-ABSteppedProgressBar/Pods/Local Podspecs/ABSteppedProgressBar.podspec.json +++ b/Exemple-ABSteppedProgressBar/Pods/Local Podspecs/ABSteppedProgressBar.podspec.json @@ -1,6 +1,6 @@ { "name": "ABSteppedProgressBar", - "version": "0.0.3", + "version": "0.0.4", "summary": "Simple and customisable stepped progress bar for iOS written in Swift", "platforms": { "ios": "8.0" @@ -12,7 +12,7 @@ "source_files": "Sources/*.swift", "source": { "git": "https://github.com/antoninbiret/ABSteppedProgressBar.git", - "tag": "0.0.3" + "tag": "0.0.4" }, "requires_arc": true, "frameworks": "Foundation", diff --git a/Exemple-ABSteppedProgressBar/Pods/Manifest.lock b/Exemple-ABSteppedProgressBar/Pods/Manifest.lock index b3d85fb..65c6a16 100644 --- a/Exemple-ABSteppedProgressBar/Pods/Manifest.lock +++ b/Exemple-ABSteppedProgressBar/Pods/Manifest.lock @@ -1,5 +1,5 @@ PODS: - - ABSteppedProgressBar (0.0.3) + - ABSteppedProgressBar (0.0.4) DEPENDENCIES: - ABSteppedProgressBar (from `../`) @@ -9,7 +9,7 @@ EXTERNAL SOURCES: :path: ../ SPEC CHECKSUMS: - ABSteppedProgressBar: 2f4f51ad45a9610f15fb696e2447482e690210c5 + ABSteppedProgressBar: 931e2f628e425cd3491a1db6efc59c12ff991981 PODFILE CHECKSUM: 6a8e347d3f7d25053b7843d2d2f4b942079e6494 diff --git a/Exemple-ABSteppedProgressBar/Pods/Pods.xcodeproj/xcuserdata/antoninbiret.xcuserdatad/xcschemes/xcschememanagement.plist b/Exemple-ABSteppedProgressBar/Pods/Pods.xcodeproj/xcuserdata/antoninbiret.xcuserdatad/xcschemes/xcschememanagement.plist index 76ce98b..975f062 100644 --- a/Exemple-ABSteppedProgressBar/Pods/Pods.xcodeproj/xcuserdata/antoninbiret.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Exemple-ABSteppedProgressBar/Pods/Pods.xcodeproj/xcuserdata/antoninbiret.xcuserdatad/xcschemes/xcschememanagement.plist @@ -17,16 +17,6 @@ SuppressBuildableAutocreation - 545ACB920FF64C043AD39D2756679314 - - primary - - - A1C1F833002BA353DFA14C3E9F6A7DAC - - primary - - B0EAD042C17521457347A94AEADE93A4 primary diff --git a/Exemple-ABSteppedProgressBar/Pods/Target Support Files/ABSteppedProgressBar/Info.plist b/Exemple-ABSteppedProgressBar/Pods/Target Support Files/ABSteppedProgressBar/Info.plist index 3f03870..43a5857 100644 --- a/Exemple-ABSteppedProgressBar/Pods/Target Support Files/ABSteppedProgressBar/Info.plist +++ b/Exemple-ABSteppedProgressBar/Pods/Target Support Files/ABSteppedProgressBar/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.0.3 + 0.0.4 CFBundleSignature ???? CFBundleVersion From 994519f0f0bb7d9918b35937112461a000461be9 Mon Sep 17 00:00:00 2001 From: Antonin Biret Date: Sun, 31 Jul 2016 22:15:47 +0200 Subject: [PATCH 2/2] Fixed orientation changes issue --- Sources/ABSteppedProgessBar.swift | 243 ++++++++++++++++++++---------- 1 file changed, 165 insertions(+), 78 deletions(-) diff --git a/Sources/ABSteppedProgessBar.swift b/Sources/ABSteppedProgessBar.swift index a6f6515..a1b9d1c 100644 --- a/Sources/ABSteppedProgessBar.swift +++ b/Sources/ABSteppedProgessBar.swift @@ -28,12 +28,16 @@ import CoreGraphics @IBDesignable public class ABSteppedProgressBar: UIView { + //MARK: - Public properties + + /// The number of displayed points in the component @IBInspectable public var numberOfPoints: Int = 3 { didSet { self.setNeedsDisplay() } } + /// The current selected index public var currentIndex: Int = 0 { willSet(newValue){ if let delegate = self.delegate { @@ -46,8 +50,7 @@ import CoreGraphics } } - private var previousIndex: Int = 0 - + /// The line height between points @IBInspectable public var lineHeight: CGFloat = 0.0 { didSet { self.setNeedsDisplay() @@ -63,6 +66,7 @@ import CoreGraphics } } + /// The point's radius @IBInspectable public var radius: CGFloat = 0.0 { didSet { self.setNeedsDisplay() @@ -78,6 +82,7 @@ import CoreGraphics } } + /// The progress points's raduis @IBInspectable public var progressRadius: CGFloat = 0.0 { didSet { maskLayer.cornerRadius = progressRadius @@ -94,6 +99,7 @@ import CoreGraphics } } + /// The progress line height between points @IBInspectable public var progressLineHeight: CGFloat = 0.0 { didSet { self.setNeedsDisplay() @@ -109,55 +115,98 @@ import CoreGraphics } } + /// The selection animation duration @IBInspectable public var stepAnimationDuration: CFTimeInterval = 0.4 - @IBInspectable public var displayNumbers: Bool = true { + /// True if some text should be rendered in the step points. The text value is provided by the delegate + @IBInspectable public var displayStepText: Bool = true { didSet { self.setNeedsDisplay() } } - public var numbersFont: UIFont? { + /// The text font in the step points + public var stepTextFont: UIFont? { didSet { self.setNeedsDisplay() } } - public var numbersColor: UIColor? { + /// The text color in the step points + public var stepTextColor: UIColor? { didSet { self.setNeedsDisplay() } } + + /// The component's background color @IBInspectable public var backgroundShapeColor: UIColor = UIColor(red: 166.0/255.0, green: 160.0/255.0, blue: 151.0/255.0, alpha: 0.8) { didSet { self.setNeedsDisplay() } } + /// The component selected background color @IBInspectable public var selectedBackgoundColor: UIColor = UIColor(red: 150.0/255.0, green: 24.0/255.0, blue: 33.0/255.0, alpha: 1.0) { didSet { self.setNeedsDisplay() } } + /// The component's delegate public weak var delegate: ABSteppedProgressBarDelegate? - private var backgroundLayer: CAShapeLayer = CAShapeLayer() - private var progressLayer: CAShapeLayer = CAShapeLayer() - private var maskLayer: CAShapeLayer = CAShapeLayer() - private var centerPoints = Array() + //MARK: - Deprecated properties + + @available(*, deprecated=0.0.5, message="Use `displayTextIndexes` instead") + @IBInspectable public var displayNumbers: Bool = true { + didSet { + self.displayStepText = self.displayNumbers + } + } + + @available(*, deprecated=0.0.5, message="Use `stepTextFont` instead") + public var numbersFont: UIFont? { + didSet { + self.stepTextFont = self.numbersFont + } + } + + @available(*, deprecated=0.0.5, message="Use `stepTextColor` instead") + public var numbersColor: UIColor? { + didSet { + self.stepTextColor = self.numbersColor + } + } + + //MARK: - Private properties + + private var backgroundLayer = CAShapeLayer() + + private var progressLayer = CAShapeLayer() + + private var maskLayer = CAShapeLayer() + + private var centerPoints = [CGPoint]() + + private var _textLayers = [Int:CATextLayer]() + + private var previousIndex: Int = 0 private var animationRendering = false + //MARK: - Life cycle + public override init(frame: CGRect) { super.init(frame: frame) - commonInit() + self.commonInit() + self.backgroundColor = UIColor.clearColor() } required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - commonInit() + self.commonInit() } convenience init() { @@ -170,20 +219,18 @@ import CoreGraphics self.addGestureRecognizer(tapGestureRecognizer) self.addGestureRecognizer(swipeGestureRecognizer) - - self.backgroundColor = UIColor.clearColor() - - self.layer.addSublayer(backgroundLayer) - self.layer.addSublayer(progressLayer) - progressLayer.mask = maskLayer + self.layer.addSublayer(self.backgroundLayer) + self.layer.addSublayer(self.progressLayer) + self.progressLayer.mask = self.maskLayer self.contentMode = UIViewContentMode.Redraw } - override public func drawRect(rect: CGRect) { super.drawRect(rect) + self.centerPoints.removeAll() + let largerRadius = fmax(_radius, _progressRadius) let distanceBetweenCircles = (self.bounds.width - (CGFloat(numberOfPoints) * 2 * largerRadius)) / CGFloat(numberOfPoints - 1) @@ -195,56 +242,26 @@ import CoreGraphics xCursor += 2 * largerRadius + distanceBetweenCircles } - let progressCenterPoints = Array(centerPoints[0..<(currentIndex+1)]) - if(!animationRendering) { - if let bgPath = shapePath(centerPoints, aRadius: _radius, aLineHeight: _lineHeight) { - backgroundLayer.path = bgPath.CGPath - backgroundLayer.fillColor = backgroundShapeColor.CGColor - } + let bgPath = self._shapePath(self.centerPoints, aRadius: _radius, aLineHeight: _lineHeight) + backgroundLayer.path = bgPath.CGPath + backgroundLayer.fillColor = backgroundShapeColor.CGColor - if let progressPath = shapePath(centerPoints, aRadius: _progressRadius, aLineHeight: _progressLineHeight) { - progressLayer.path = progressPath.CGPath - progressLayer.fillColor = selectedBackgoundColor.CGColor - } + let progressPath = self._shapePath(self.centerPoints, aRadius: _progressRadius, aLineHeight: _progressLineHeight) + progressLayer.path = progressPath.CGPath + progressLayer.fillColor = selectedBackgoundColor.CGColor - if(displayNumbers) { - for i in 0...(numberOfPoints - 1) { - let centerPoint = centerPoints[i] - let textLayer = CATextLayer() - - var textLayerFont = UIFont.boldSystemFontOfSize(_progressRadius) - textLayer.contentsScale = UIScreen.mainScreen().scale - - if let nFont = self.numbersFont { - textLayerFont = nFont - } - textLayer.font = CTFontCreateWithName(textLayerFont.fontName as CFStringRef, textLayerFont.pointSize, nil) - textLayer.fontSize = textLayerFont.pointSize - - if let nColor = self.numbersColor { - textLayer.foregroundColor = nColor.CGColor - } - - if let text = self.delegate?.progressBar?(self, textAtIndex: i) { - textLayer.string = text - } else { - textLayer.string = "\(i)" - } - - textLayer.sizeWidthToFit() - - textLayer.frame = CGRectMake(centerPoint.x - textLayer.bounds.width/2, centerPoint.y - textLayer.bounds.height/2, textLayer.bounds.width, textLayer.bounds.height) - - self.layer.addSublayer(textLayer) - } + if(self.displayNumbers) { + self.renderTextIndexes() } } + let progressCenterPoints = Array(centerPoints[0..<(currentIndex+1)]) + if let currentProgressCenterPoint = progressCenterPoints.last { - let maskPath = self.maskPath(currentProgressCenterPoint) + let maskPath = self._maskPath(currentProgressCenterPoint) maskLayer.path = maskPath.CGPath CATransaction.begin() @@ -267,11 +284,75 @@ import CoreGraphics maskLayer.addAnimation(progressAnimation, forKey: "progressAnimation") CATransaction.commit() } - previousIndex = currentIndex + self.previousIndex = self.currentIndex + } + + /** + Render the text indexes + */ + private func renderTextIndexes() { + + for i in 0...(numberOfPoints - 1) { + let centerPoint = centerPoints[i] + + let textLayer = self._textLayer(atIndex: i) + + var textLayerFont = UIFont.boldSystemFontOfSize(self._progressRadius) + textLayer.contentsScale = UIScreen.mainScreen().scale + + if let nFont = self.numbersFont { + textLayerFont = nFont + } + textLayer.font = CTFontCreateWithName(textLayerFont.fontName as CFStringRef, textLayerFont.pointSize, nil) + textLayer.fontSize = textLayerFont.pointSize + + if let nColor = self.numbersColor { + textLayer.foregroundColor = nColor.CGColor + } + + if let text = self.delegate?.progressBar?(self, textAtIndex: i) { + textLayer.string = text + } else { + textLayer.string = "\(i)" + } + + textLayer.sizeWidthToFit() + + textLayer.frame = CGRectMake(centerPoint.x - textLayer.bounds.width/2, centerPoint.y - textLayer.bounds.height/2, textLayer.bounds.width, textLayer.bounds.height) + } } + /** + Provide a text layer for the given index. If it's not in cache, it'll be instanciated. + + - parameter index: The index where the layer will be used + + - returns: The text layer + */ + private func _textLayer(atIndex index: Int) -> CATextLayer { + + var textLayer: CATextLayer + if let _textLayer = self._textLayers[index] { + textLayer = _textLayer + } else { + textLayer = CATextLayer() + self._textLayers[index] = textLayer + } + self.layer.addSublayer(textLayer) + + return textLayer + } - func shapePath(centerPoints: Array, aRadius: CGFloat, aLineHeight: CGFloat) -> UIBezierPath? { + /** + Compte a progress path + + - parameter centerPoints: The center points corresponding to the indexes + - parameter aRadius: The index radius + - parameter aLineHeight: The line height between each index + + - returns: The computed path + */ + private func _shapePath(centerPoints: Array, aRadius: CGFloat, aLineHeight: CGFloat) -> UIBezierPath { let nbPoint = centerPoints.count @@ -337,7 +418,6 @@ import CoreGraphics path.addArcWithCenter(CGPointMake(centerPoint.x, centerPoint.y), radius: aRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true) - if(i < nbPoint - 1) { xCursor += aRadius + distanceBetweenCircles path.addLineToPoint(CGPointMake(xCursor, centerPoint.y - aLineHeight / 2.0)) @@ -351,15 +431,17 @@ import CoreGraphics return path } - func progressMaskPath(currentProgressCenterPoint: CGPoint) -> UIBezierPath { - let maskPath = UIBezierPath(rect: CGRectMake(0.0, 0.0, currentProgressCenterPoint.x + _progressRadius, self.bounds.height)) - return maskPath - } - - func maskPath(currentProgressCenterPoint: CGPoint) -> UIBezierPath { + /** + Compute the mask path + + - parameter currentProgressCenterPoint: The current progress index's center point + + - returns: The computed mask path + */ + private func _maskPath(currentProgressCenterPoint: CGPoint) -> UIBezierPath { - let angle = _progressLineHeight / 2.0 / _progressRadius; - let xOffset = cos(angle) * _progressRadius + let angle = self._progressLineHeight / 2.0 / self._progressRadius; + let xOffset = cos(angle) * self._progressRadius let maskPath = UIBezierPath() @@ -367,9 +449,9 @@ import CoreGraphics maskPath.addLineToPoint(CGPointMake(currentProgressCenterPoint.x + xOffset, 0.0)) - maskPath.addLineToPoint(CGPointMake(currentProgressCenterPoint.x + xOffset, currentProgressCenterPoint.y - _progressLineHeight)) + maskPath.addLineToPoint(CGPointMake(currentProgressCenterPoint.x + xOffset, currentProgressCenterPoint.y - self._progressLineHeight)) - maskPath.addArcWithCenter(currentProgressCenterPoint, radius: _progressRadius, startAngle: -angle, endAngle: angle, clockwise: true) + maskPath.addArcWithCenter(currentProgressCenterPoint, radius: self._progressRadius, startAngle: -angle, endAngle: angle, clockwise: true) maskPath.addLineToPoint(CGPointMake(currentProgressCenterPoint.x + xOffset, self.bounds.height)) @@ -379,8 +461,12 @@ import CoreGraphics return maskPath } - - func gestureAction(gestureRecognizer:UIGestureRecognizer) { + /** + Respond to the user action + + - parameter gestureRecognizer: The gesture recognizer responsible for the action + */ + func gestureAction(gestureRecognizer: UIGestureRecognizer) { if(gestureRecognizer.state == UIGestureRecognizerState.Ended || gestureRecognizer.state == UIGestureRecognizerState.Changed ) { @@ -390,20 +476,21 @@ import CoreGraphics var selectedIndex = 0 - for (index, point) in centerPoints.enumerate() { + for (index, point) in self.centerPoints.enumerate() { let distance = touchPoint.distanceWith(point) if(distance < smallestDistance) { smallestDistance = distance selectedIndex = index } } - if(currentIndex != selectedIndex) { + + if(self.currentIndex != selectedIndex) { if let canSelect = self.delegate?.progressBar?(self, canSelectItemAtIndex: selectedIndex) { if (canSelect) { - currentIndex = selectedIndex + self.currentIndex = selectedIndex } } else { - currentIndex = selectedIndex + self.currentIndex = selectedIndex } } }