@@ -11,79 +11,72 @@ import UIKit
11@IBDesignable public class GMStepper: UIControl {
11@IBDesignable public class GMStepper: UIControl {
13 /// Current value of the stepper. Defaults to 0.
13 /// Current value of the stepper. Defaults to 0.
14− @objc @IBInspectable public var value: Double = 0 {
14+ @IBInspectable public var value: Double = 0 {
16 value = min(maximumValue, max(minimumValue, value))
16 value = min(maximumValue, max(minimumValue, value))
18 let isInteger = floor(value) == value
18 let isInteger = floor(value) == value
21− // If we have items, we will display them as steps
24− if isInteger && stepValue == 1.0 && items.count > 0 {
25− label.text = items[Int(value)]
27− else if showIntegerIfDoubleIsInteger && isInteger {
20+ if showIntegerIfDoubleIsInteger && isInteger {
28 label.text = String(stringInterpolationSegment: Int(value))
21 label.text = String(stringInterpolationSegment: Int(value))
30 label.text = String(stringInterpolationSegment: value)
23 label.text = String(stringInterpolationSegment: value)
33 if oldValue != value {
26 if oldValue != value {
34− sendActions(for: .valueChanged)
27+ sendActionsForControlEvents(.ValueChanged)
39 /// Minimum value. Must be less than maximumValue. Defaults to 0.
32 /// Minimum value. Must be less than maximumValue. Defaults to 0.
40− @objc @IBInspectable public var minimumValue: Double = 0 {
33+ @IBInspectable public var minimumValue: Double = 0 {
42 value = min(maximumValue, max(minimumValue, value))
35 value = min(maximumValue, max(minimumValue, value))
46 /// Maximum value. Must be more than minimumValue. Defaults to 100.
39 /// Maximum value. Must be more than minimumValue. Defaults to 100.
47− @objc @IBInspectable public var maximumValue: Double = 100 {
40+ @IBInspectable public var maximumValue: Double = 100 {
49 value = min(maximumValue, max(minimumValue, value))
42 value = min(maximumValue, max(minimumValue, value))
53 /// Step/Increment value as in UIStepper. Defaults to 1.
46 /// Step/Increment value as in UIStepper. Defaults to 1.
54− @objc @IBInspectable public var stepValue: Double = 1
47+ @IBInspectable public var stepValue: Double = 1
56 /// The same as UIStepper's autorepeat. If true, holding on the buttons or keeping the pan gesture alters the value repeatedly. Defaults to true.
49 /// The same as UIStepper's autorepeat. If true, holding on the buttons or keeping the pan gesture alters the value repeatedly. Defaults to true.
57− @objc @IBInspectable public var autorepeat: Bool = true
50+ @IBInspectable public var autorepeat: Bool = true
59 /// If the value is integer, it is shown without floating point.
52 /// If the value is integer, it is shown without floating point.
60− @objc @IBInspectable public var showIntegerIfDoubleIsInteger: Bool = true
53+ @IBInspectable public var showIntegerIfDoubleIsInteger: Bool = true
62 /// Text on the left button. Be sure that it fits in the button. Defaults to "−".
55 /// Text on the left button. Be sure that it fits in the button. Defaults to "−".
63− @objc @IBInspectable public var leftButtonText: String = "−" {
56+ @IBInspectable public var leftButtonText: String = "−" {
65− leftButton.setTitle(leftButtonText, for: .normal)
58+ leftButton.setTitle(leftButtonText, forState: .Normal)
69 /// Text on the right button. Be sure that it fits in the button. Defaults to "+".
62 /// Text on the right button. Be sure that it fits in the button. Defaults to "+".
70− @objc @IBInspectable public var rightButtonText: String = "+" {
63+ @IBInspectable public var rightButtonText: String = "+" {
72− rightButton.setTitle(rightButtonText, for: .normal)
65+ rightButton.setTitle(rightButtonText, forState: .Normal)
76 /// Text color of the buttons. Defaults to white.
69 /// Text color of the buttons. Defaults to white.
77− @objc @IBInspectable public var buttonsTextColor: UIColor = UIColor.white {
70+ @IBInspectable public var buttonsTextColor: UIColor = UIColor.whiteColor() {
79 for button in [leftButton, rightButton] {
72 for button in [leftButton, rightButton] {
80− button.setTitleColor(buttonsTextColor, for: .normal)
73+ button.setTitleColor(buttonsTextColor, forState: .Normal)
85 /// Background color of the buttons. Defaults to dark blue.
78 /// Background color of the buttons. Defaults to dark blue.
86− @objc @IBInspectable public var buttonsBackgroundColor: UIColor = UIColor(red:0.21, green:0.5, blue:0.74, alpha:1) {
79+ @IBInspectable public var buttonsBackgroundColor: UIColor = UIColor(red:0.21, green:0.5, blue:0.74, alpha:1) {
88 for button in [leftButton, rightButton] {
81 for button in [leftButton, rightButton] {
89 button.backgroundColor = buttonsBackgroundColor
82 button.backgroundColor = buttonsBackgroundColor
@@ -93,7 +86,7 @@ import UIKit
95 /// Font of the buttons. Defaults to AvenirNext-Bold, 20.0 points in size.
88 /// Font of the buttons. Defaults to AvenirNext-Bold, 20.0 points in size.
96− @objc public var buttonsFont = UIFont(name: "AvenirNext-Bold", size: 20.0)! {
89+ public var buttonsFont = UIFont(name: "AvenirNext-Bold", size: 20.0)! {
98 for button in [leftButton, rightButton] {
91 for button in [leftButton, rightButton] {
99 button.titleLabel?.font = buttonsFont
92 button.titleLabel?.font = buttonsFont
@@ -102,59 +95,36 @@ import UIKit
104 /// Text color of the middle label. Defaults to white.
97 /// Text color of the middle label. Defaults to white.
105− @objc @IBInspectable public var labelTextColor: UIColor = UIColor.white {
98+ @IBInspectable public var labelTextColor: UIColor = UIColor.whiteColor() {
107 label.textColor = labelTextColor
100 label.textColor = labelTextColor
111 /// Text color of the middle label. Defaults to lighter blue.
104 /// Text color of the middle label. Defaults to lighter blue.
112− @objc @IBInspectable public var labelBackgroundColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1) {
105+ @IBInspectable public var labelBackgroundColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1) {
114 label.backgroundColor = labelBackgroundColor
107 label.backgroundColor = labelBackgroundColor
118 /// Font of the middle label. Defaults to AvenirNext-Bold, 25.0 points in size.
111 /// Font of the middle label. Defaults to AvenirNext-Bold, 25.0 points in size.
119− @objc public var labelFont = UIFont(name: "AvenirNext-Bold", size: 25.0)! {
112+ public var labelFont = UIFont(name: "AvenirNext-Bold", size: 25.0)! {
121 label.font = labelFont
114 label.font = labelFont
124− /// Corner radius of the middle label. Defaults to 0.
125− @objc @IBInspectable public var labelCornerRadius: CGFloat = 0 {
127− label.layer.cornerRadius = labelCornerRadius
132 /// Corner radius of the stepper's layer. Defaults to 4.0.
118 /// Corner radius of the stepper's layer. Defaults to 4.0.
133− @objc @IBInspectable public var cornerRadius: CGFloat = 4.0 {
119+ @IBInspectable public var cornerRadius: CGFloat = 4.0 {
135 layer.cornerRadius = cornerRadius
121 layer.cornerRadius = cornerRadius
136 clipsToBounds = true
122 clipsToBounds = true
140− /// Border width of the stepper and middle label's layer. Defaults to 0.0.
141− @objc @IBInspectable public var borderWidth: CGFloat = 0.0 {
143− layer.borderWidth = borderWidth
144− label.layer.borderWidth = borderWidth
148− /// Color of the border of the stepper and middle label's layer. Defaults to clear color.
149− @objc @IBInspectable public var borderColor: UIColor = UIColor.clear {
151− layer.borderColor = borderColor.cgColor
152− label.layer.borderColor = borderColor.cgColor
156 /// Percentage of the middle label's width. Must be between 0 and 1. Defaults to 0.5. Be sure that it is wide enough to show the value.
126 /// Percentage of the middle label's width. Must be between 0 and 1. Defaults to 0.5. Be sure that it is wide enough to show the value.
157− @objc @IBInspectable public var labelWidthWeight: CGFloat = 0.5 {
127+ @IBInspectable public var labelWidthWeight: CGFloat = 0.5 {
159 labelWidthWeight = min(1, max(0, labelWidthWeight))
129 labelWidthWeight = min(1, max(0, labelWidthWeight))
160 setNeedsLayout()
130 setNeedsLayout()
@@ -162,7 +132,7 @@ import UIKit
164 /// Color of the flashing animation on the buttons in case the value hit the limit.
134 /// Color of the flashing animation on the buttons in case the value hit the limit.
165− @objc @IBInspectable public var limitHitAnimationColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1)
135+ @IBInspectable public var limitHitAnimationColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1)
168 Width of the sliding animation. When buttons clicked, the middle label does a slide animation towards to the clicked button. Defaults to 5.
138 Width of the sliding animation. When buttons clicked, the middle label does a slide animation towards to the clicked button. Defaults to 5.
@@ -170,40 +140,38 @@ import UIKit
170 let labelSlideLength: CGFloat = 5
140 let labelSlideLength: CGFloat = 5
172 /// Duration of the sliding animation
142 /// Duration of the sliding animation
173− let labelSlideDuration = TimeInterval(0.1)
143+ let labelSlideDuration = NSTimeInterval(0.1)
175 /// Duration of the animation when the value hits the limit.
145 /// Duration of the animation when the value hits the limit.
176− let limitHitAnimationDuration = TimeInterval(0.1)
146+ let limitHitAnimationDuration = NSTimeInterval(0.1)
178 lazy var leftButton: UIButton = {
148 lazy var leftButton: UIButton = {
179 let button = UIButton()
149 let button = UIButton()
180− button.setTitle(self.leftButtonText, for: .normal)
150+ button.setTitle(self.leftButtonText, forState: .Normal)
181− button.setTitleColor(self.buttonsTextColor, for: .normal)
151+ button.setTitleColor(self.buttonsTextColor, forState: .Normal)
182 button.backgroundColor = self.buttonsBackgroundColor
152 button.backgroundColor = self.buttonsBackgroundColor
183 button.titleLabel?.font = self.buttonsFont
153 button.titleLabel?.font = self.buttonsFont
184− button.addTarget(self, action: #selector(GMStepper.leftButtonTouchDown), for: .touchDown)
154+ button.addTarget(self, action: "leftButtonTouchDown:", forControlEvents: .TouchDown)
185− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpInside)
155+ button.addTarget(self, action: "buttonTouchUp:", forControlEvents: UIControlEvents.TouchUpInside)
186− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpOutside)
156+ button.addTarget(self, action: "buttonTouchUp:", forControlEvents: UIControlEvents.TouchUpOutside)
187− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchCancel)
188 return button
157 return button
191 lazy var rightButton: UIButton = {
160 lazy var rightButton: UIButton = {
192 let button = UIButton()
161 let button = UIButton()
193− button.setTitle(self.rightButtonText, for: .normal)
162+ button.setTitle(self.rightButtonText, forState: .Normal)
194− button.setTitleColor(self.buttonsTextColor, for: .normal)
163+ button.setTitleColor(self.buttonsTextColor, forState: .Normal)
195 button.backgroundColor = self.buttonsBackgroundColor
164 button.backgroundColor = self.buttonsBackgroundColor
196 button.titleLabel?.font = self.buttonsFont
165 button.titleLabel?.font = self.buttonsFont
197− button.addTarget(self, action: #selector(GMStepper.rightButtonTouchDown), for: .touchDown)
166+ button.addTarget(self, action: "rightButtonTouchDown:", forControlEvents: .TouchDown)
198− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpInside)
167+ button.addTarget(self, action: "buttonTouchUp:", forControlEvents: UIControlEvents.TouchUpInside)
199− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchUpOutside)
168+ button.addTarget(self, action: "buttonTouchUp:", forControlEvents: UIControlEvents.TouchUpOutside)
200− button.addTarget(self, action: #selector(GMStepper.buttonTouchUp), for: .touchCancel)
201 return button
169 return button
204 lazy var label: UILabel = {
172 lazy var label: UILabel = {
205 let label = UILabel()
173 let label = UILabel()
206− label.textAlignment = .center
174+ label.textAlignment = .Center
207 if self.showIntegerIfDoubleIsInteger && floor(self.value) == self.value {
175 if self.showIntegerIfDoubleIsInteger && floor(self.value) == self.value {
208 label.text = String(stringInterpolationSegment: Int(self.value))
176 label.text = String(stringInterpolationSegment: Int(self.value))
@@ -212,10 +180,8 @@ import UIKit
212 label.textColor = self.labelTextColor
180 label.textColor = self.labelTextColor
213 label.backgroundColor = self.labelBackgroundColor
181 label.backgroundColor = self.labelBackgroundColor
214 label.font = self.labelFont
182 label.font = self.labelFont
215− label.layer.cornerRadius = self.labelCornerRadius
183+ label.userInteractionEnabled = true
216− label.layer.masksToBounds = true
217− label.isUserInteractionEnabled = true
218− let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(GMStepper.handlePan))
184+ let panRecognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
219 panRecognizer.maximumNumberOfTouches = 1
185 panRecognizer.maximumNumberOfTouches = 1
220 label.addGestureRecognizer(panRecognizer)
186 label.addGestureRecognizer(panRecognizer)
221 return label
187 return label
@@ -243,33 +209,9 @@ import UIKit
248− @objc public var items : [String] = [] {
250− let isInteger = floor(value) == value
253− // If we have items, we will display them as steps
256− if isInteger && stepValue == 1.0 && items.count > 0 {
258− var value = Int(self.value)
260− if value >= items.count {
261− value = items.count - 1
262− self.value = Double(value)
265− label.text = items[value]
271 /// Timer used for autorepeat option
213 /// Timer used for autorepeat option
272− var timer: Timer?
214+ var timer: NSTimer?
274 /** When UIStepper reaches its top speed, it alters the value with a time interval of ~0.05 sec.
216 /** When UIStepper reaches its top speed, it alters the value with a time interval of ~0.05 sec.
275 The user pressing and holding on the stepper repeatedly:
217 The user pressing and holding on the stepper repeatedly:
@@ -277,7 +219,7 @@ import UIKit
277 - For the next 1.5 sec, it changes the value every 0.1 sec.
219 - For the next 1.5 sec, it changes the value every 0.1 sec.
278 - Then, every 0.05 sec.
220 - Then, every 0.05 sec.
280− let timerInterval = TimeInterval(0.05)
222+ let timerInterval = NSTimeInterval(0.05)
282 /// Check the handleTimerFire: function. While it is counting the number of fires, it decreases the mod value so that the value is altered more frequently.
224 /// Check the handleTimerFire: function. While it is counting the number of fires, it decreases the mod value so that the value is altered more frequently.
283 var timerFireCount = 0
225 var timerFireCount = 0
@@ -291,12 +233,12 @@ import UIKit
294− @objc required public init?(coder aDecoder: NSCoder) {
236+ required public init?(coder aDecoder: NSCoder) {
295 super.init(coder: aDecoder)
237 super.init(coder: aDecoder)
299− @objc public override init(frame: CGRect) {
241+ public override init(frame: CGRect) {
300 super.init(frame: frame)
242 super.init(frame: frame)
@@ -309,9 +251,8 @@ import UIKit
309 backgroundColor = buttonsBackgroundColor
251 backgroundColor = buttonsBackgroundColor
310 layer.cornerRadius = cornerRadius
252 layer.cornerRadius = cornerRadius
311 clipsToBounds = true
253 clipsToBounds = true
312− labelOriginalCenter = label.center
314− NotificationCenter.default.addObserver(self, selector: #selector(GMStepper.reset), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
255+ NSNotificationCenter.defaultCenter().addObserver(self, selector: "reset", name: UIApplicationWillResignActiveNotification, object: nil)
317 public override func layoutSubviews() {
258 public override func layoutSubviews() {
@@ -337,7 +278,7 @@ import UIKit
339 resetTimer()
280 resetTimer()
340− NotificationCenter.default.removeObserver(self)
281+ NSNotificationCenter.defaultCenter().removeObserver(self)
343 /// Useful closure for logging the timer interval. You can call this in the timer handler to test the autorepeat option. Not used in the current implementation.
284 /// Useful closure for logging the timer interval. You can call this in the timer handler to test the autorepeat option. Not used in the current implementation.
@@ -356,17 +297,17 @@ import UIKit
357// MARK: Pan Gesture
298// MARK: Pan Gesture
358extension GMStepper {
299extension GMStepper {
359− @objc func handlePan(gesture: UIPanGestureRecognizer) {
300+ func handlePan(gesture: UIPanGestureRecognizer) {
360 switch gesture.state {
301 switch gesture.state {
361− case .began:
302+ case .Began:
362− leftButton.isEnabled = false
303+ leftButton.enabled = false
363− rightButton.isEnabled = false
304+ rightButton.enabled = false
364− case .changed:
305+ case .Changed:
365− let translation = gesture.translation(in: label)
306+ let translation = gesture.translationInView(label)
366− gesture.setTranslation(CGPoint.zero, in: label)
307+ gesture.setTranslation(CGPointZero, inView: label)
368− let slidingRight = gesture.velocity(in: label).x > 0
309+ let slidingRight = gesture.velocityInView(label).x > 0
369− let slidingLeft = gesture.velocity(in: label).x < 0
310+ let slidingLeft = gesture.velocityInView(label).x < 0
371 // Move the label with pan
312 // Move the label with pan
372 if slidingRight {
313 if slidingRight {
@@ -399,23 +340,23 @@ extension GMStepper {
399 self.rightButton.backgroundColor = self.buttonsBackgroundColor
340 self.rightButton.backgroundColor = self.buttonsBackgroundColor
400 self.leftButton.backgroundColor = self.buttonsBackgroundColor
341 self.leftButton.backgroundColor = self.buttonsBackgroundColor
402− case .ended, .cancelled, .failed:
343+ case .Ended, .Cancelled, .Failed:
409− @objc func reset() {
350+ func reset() {
410 panState = .Stable
351 panState = .Stable
411 stepperState = .Stable
352 stepperState = .Stable
412 resetTimer()
353 resetTimer()
414− leftButton.isEnabled = true
355+ leftButton.enabled = true
415− rightButton.isEnabled = true
356+ rightButton.enabled = true
416− label.isUserInteractionEnabled = true
357+ label.userInteractionEnabled = true
418− UIView.animate(withDuration: self.labelSlideDuration, animations: {
359+ UIView.animateWithDuration(self.labelSlideDuration, animations: {
419 self.label.center = self.labelOriginalCenter
360 self.label.center = self.labelOriginalCenter
420 self.rightButton.backgroundColor = self.buttonsBackgroundColor
361 self.rightButton.backgroundColor = self.buttonsBackgroundColor
421 self.leftButton.backgroundColor = self.buttonsBackgroundColor
362 self.leftButton.backgroundColor = self.buttonsBackgroundColor
@@ -425,9 +366,9 @@ extension GMStepper {
426// MARK: Button Events
367// MARK: Button Events
427extension GMStepper {
368extension GMStepper {
428− @objc func leftButtonTouchDown(button: UIButton) {
369+ func leftButtonTouchDown(button: UIButton) {
429− rightButton.isEnabled = false
370+ rightButton.enabled = false
430− label.isUserInteractionEnabled = false
371+ label.userInteractionEnabled = false
431 resetTimer()
372 resetTimer()
433 if value == minimumValue {
374 if value == minimumValue {
@@ -439,9 +380,9 @@ extension GMStepper {
442− @objc func rightButtonTouchDown(button: UIButton) {
383+ func rightButtonTouchDown(button: UIButton) {
443− leftButton.isEnabled = false
384+ leftButton.enabled = false
444− label.isUserInteractionEnabled = false
385+ label.userInteractionEnabled = false
445 resetTimer()
386 resetTimer()
447 if value == maximumValue {
388 if value == maximumValue {
@@ -452,7 +393,7 @@ extension GMStepper {
455− @objc func buttonTouchUp(button: UIButton) {
396+ func buttonTouchUp(button: UIButton) {
@@ -461,20 +402,20 @@ extension GMStepper {
461extension GMStepper {
402extension GMStepper {
463 func animateSlideLeft() {
404 func animateSlideLeft() {
464− UIView.animate(withDuration: labelSlideDuration) {
405+ UIView.animateWithDuration(labelSlideDuration) {
465 self.label.center.x -= self.labelSlideLength
406 self.label.center.x -= self.labelSlideLength
469 func animateSlideRight() {
410 func animateSlideRight() {
470− UIView.animate(withDuration: labelSlideDuration) {
411+ UIView.animateWithDuration(labelSlideDuration) {
471 self.label.center.x += self.labelSlideLength
412 self.label.center.x += self.labelSlideLength
475 func animateToOriginalPosition() {
416 func animateToOriginalPosition() {
476 if self.label.center != self.labelOriginalCenter {
417 if self.label.center != self.labelOriginalCenter {
477− UIView.animate(withDuration: labelSlideDuration) {
418+ UIView.animateWithDuration(labelSlideDuration) {
478 self.label.center = self.labelOriginalCenter
419 self.label.center = self.labelOriginalCenter
@@ -482,14 +423,14 @@ extension GMStepper {
483 func animateLimitHitIfNeeded() {
424 func animateLimitHitIfNeeded() {
484 if value == minimumValue {
425 if value == minimumValue {
485− animateLimitHitForButton(button: leftButton)
426+ animateLimitHitForButton(leftButton)
486 } else if value == maximumValue {
427 } else if value == maximumValue {
487− animateLimitHitForButton(button: rightButton)
428+ animateLimitHitForButton(rightButton)
491 func animateLimitHitForButton(button: UIButton){
432 func animateLimitHitForButton(button: UIButton){
492− UIView.animate(withDuration: limitHitAnimationDuration) {
433+ UIView.animateWithDuration(limitHitAnimationDuration) {
493 button.backgroundColor = self.limitHitAnimationColor
434 button.backgroundColor = self.limitHitAnimationColor
@@ -497,7 +438,7 @@ extension GMStepper {
498// MARK: Timer
439// MARK: Timer
499extension GMStepper {
440extension GMStepper {
500− @objc func handleTimerFire(timer: Timer) {
441+ func handleTimerFire(timer: NSTimer) {
501 timerFireCount += 1
442 timerFireCount += 1
503 if timerFireCount % timerFireCountModulo == 0 {
444 if timerFireCount % timerFireCountModulo == 0 {
@@ -506,7 +447,7 @@ extension GMStepper {
508 func scheduleTimer() {
449 func scheduleTimer() {
509− timer = Timer.scheduledTimer(timeInterval: timerInterval, target: self, selector: #selector(GMStepper.handleTimerFire), userInfo: nil, repeats: true)
450+ timer = NSTimer.scheduledTimerWithTimeInterval(timerInterval, target: self, selector: "handleTimerFire:", userInfo: nil, repeats: true)
512 func resetTimer() {
453 func resetTimer() {