@@ -36,6 +36,9 @@ import UIKit
39+ /// The same as UIStepper's autorepeat. If true, holding on the buttons or the pan gesture repeatedly alters value. Defaults to true.
40+ @IBInspectable public var autorepeat: Bool = true
39 /// Text on the left button. Be sure that it fits in the button. Defaults to "-".
42 /// Text on the left button. Be sure that it fits in the button. Defaults to "-".
40 @IBInspectable public var leftButtonText: String = "-" {
43 @IBInspectable public var leftButtonText: String = "-" {
@@ -121,10 +124,10 @@ import UIKit
121 private let labelSlideLength: CGFloat = 5
124 private let labelSlideLength: CGFloat = 5
123 /// Duration of the sliding animation
126 /// Duration of the sliding animation
124− private let labelSlideDuration: NSTimeInterval = 0.1
127+ private let labelSlideDuration = NSTimeInterval(0.1)
126 /// Duration of the flashing animation when the value hits the limit.
129 /// Duration of the flashing animation when the value hits the limit.
127− private let limitHitAnimationDuration: NSTimeInterval = 0.1
130+ private let limitHitAnimationDuration = NSTimeInterval(0.1)
129 /// Color of the flashing animation on the buttons in case the value hit the limit.
132 /// Color of the flashing animation on the buttons in case the value hit the limit.
130 @IBInspectable public var limitHitAnimationColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1)
133 @IBInspectable public var limitHitAnimationColor: UIColor = UIColor(red:0.26, green:0.6, blue:0.87, alpha:1)
@@ -142,6 +145,40 @@ import UIKit
143 private var panState = LabelPanState.Stale
146 private var panState = LabelPanState.Stale
148+ private var timer: NSTimer?
150+ /** When UIStepper reaches its top speed, it alters the value with a time interval of ~0.05 sec.
151+ The user pressing and holding on the stepper repeatedly:
152+ - First 2.5 sec, the stepper changes the value every 0.5 sec.
153+ - For the next 1.5 sec, it changes the value every 0.1 sec.
154+ - Then, every 0.05 sec.
156+ private let timerInterval = NSTimeInterval(0.05)
158+ /// 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.
159+ private var timerFireCount = 0
160+ private var timerFireCountModulo: Int {
161+ if timerFireCount > 80 {
162+ return 1 // 0.05 sec * 1 = 0.05 sec
163+ } else if timerFireCount > 50 {
164+ return 2 // 0.05 sec * 2 = 0.1 sec
166+ return 10 // 0.05 sec * 10 = 0.5 sec
170+ lazy var printTimerGaps: () -> () = {
171+ var prevTime: CFAbsoluteTime?
174+ var now = CFAbsoluteTimeGetCurrent()
175+ if let prevTime = prevTime {
176+ println(now - prevTime)
145 required public init(coder aDecoder: NSCoder) {
182 required public init(coder aDecoder: NSCoder) {
146 super.init(coder: aDecoder)
183 super.init(coder: aDecoder)
@@ -157,7 +194,9 @@ import UIKit
157 leftButton.setTitleColor(buttonsTextColor, forState: .Normal)
194 leftButton.setTitleColor(buttonsTextColor, forState: .Normal)
158 leftButton.backgroundColor = buttonsBackgroundColor
195 leftButton.backgroundColor = buttonsBackgroundColor
159 leftButton.titleLabel?.font = buttonsFont
196 leftButton.titleLabel?.font = buttonsFont
160− leftButton.addTarget(self, action: "leftButtonTapped:", forControlEvents: .TouchDown)
197+ leftButton.addTarget(self, action: "leftButtonTouchDown:", forControlEvents: .TouchDown)
198+ leftButton.addTarget(self, action: "leftButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpInside)
199+ leftButton.addTarget(self, action: "leftButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpOutside)
161 addSubview(leftButton)
200 addSubview(leftButton)
163 rightButton.setTitle(rightButtonText, forState: .Normal)
202 rightButton.setTitle(rightButtonText, forState: .Normal)
@@ -165,6 +204,8 @@ import UIKit
165 rightButton.backgroundColor = buttonsBackgroundColor
204 rightButton.backgroundColor = buttonsBackgroundColor
166 rightButton.titleLabel?.font = buttonsFont
205 rightButton.titleLabel?.font = buttonsFont
167 rightButton.addTarget(self, action: "rightButtonTapped:", forControlEvents: .TouchDown)
206 rightButton.addTarget(self, action: "rightButtonTapped:", forControlEvents: .TouchDown)
207+ rightButton.addTarget(self, action: "rightButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpInside)
208+ rightButton.addTarget(self, action: "rightButtonTouchUp:", forControlEvents: UIControlEvents.TouchUpOutside)
168 addSubview(rightButton)
209 addSubview(rightButton)
170 label.textAlignment = .Center
211 label.textAlignment = .Center
@@ -196,51 +237,7 @@ import UIKit
196 labelOriginalCenter = label.center
237 labelOriginalCenter = label.center
199− @objc private func leftButtonTapped(button: UIButton) {
200− if value == minimumValue {
201− animateLimitHitForButton(leftButton)
208− @objc private func rightButtonTapped(button: UIButton) {
209− if value == maximumValue {
210− animateLimitHitForButton(rightButton)
217− private func animateSlideLeft() {
218− UIView.animateWithDuration(labelSlideDuration, animations: {
219− self.label.center.x -= self.labelSlideLength
220− }, completion: { _ in
221− UIView.animateWithDuration(self.labelSlideDuration, animations: {
222− self.label.center.x += self.labelSlideLength
227− private func animateSlideRight() {
228− UIView.animateWithDuration(labelSlideDuration, animations: {
229− self.label.center.x += self.labelSlideLength
230− }, completion: { _ in
231− UIView.animateWithDuration(self.labelSlideDuration, animations: {
232− self.label.center.x -= self.labelSlideLength
237− private func animateLimitHitForButton(button: UIButton){
238− UIView.animateWithDuration(limitHitAnimationDuration, animations: {
239− button.backgroundColor = self.limitHitAnimationColor
240− }, completion: { _ in
241− button.backgroundColor = self.buttonsBackgroundColor
245 @objc private func handlePan(gesture: UIPanGestureRecognizer) {
242 @objc private func handlePan(gesture: UIPanGestureRecognizer) {
246 switch gesture.state {
243 switch gesture.state {
@@ -268,7 +265,7 @@ import UIKit
270 if value == maximumValue {
267 if value == maximumValue {
271− rightButton.backgroundColor = self.limitHitAnimationColor
268+ animateLimitHitForButton(rightButton)
273 } else if label.center.x == labelMinimumCenterX {
270 } else if label.center.x == labelMinimumCenterX {
@@ -278,7 +275,7 @@ import UIKit
280 if value == minimumValue {
277 if value == minimumValue {
281− leftButton.backgroundColor = self.limitHitAnimationColor
278+ animateLimitHitForButton(leftButton)
284 leftButton.backgroundColor = buttonsBackgroundColor
281 leftButton.backgroundColor = buttonsBackgroundColor
@@ -301,5 +298,103 @@ import UIKit
301 self.leftButton.backgroundColor = self.buttonsBackgroundColor
298 self.leftButton.backgroundColor = self.buttonsBackgroundColor
303+// MARK: Button Events
304+extension GMStepper {
305+ @objc private func leftButtonTouchDown(button: UIButton) {
306+ if value == minimumValue {
307+ animateLimitHitForButton(leftButton)
311+ scheduleTimerWithUserInfo(leftButton)
317+ @objc private func leftButtonTouchUp(button: UIButton) {
322+ @objc private func rightButtonTapped(button: UIButton) {
323+ if value == maximumValue {
324+ animateLimitHitForButton(rightButton)
328+ scheduleTimerWithUserInfo(rightButton)
334+ @objc private func rightButtonTouchUp(button: UIButton) {
341+extension GMStepper {
343+ private func animateSlideLeft() {
344+ UIView.animateWithDuration(labelSlideDuration) {
345+ self.label.center.x -= self.labelSlideLength
349+ private func animateSlideRight() {
350+ UIView.animateWithDuration(labelSlideDuration) {
351+ self.label.center.x += self.labelSlideLength
355+ private func animateToOriginalPosition() {
356+ if self.label.center != self.labelOriginalCenter {
357+ UIView.animateWithDuration(labelSlideDuration) {
358+ self.label.center = self.labelOriginalCenter
363+ private func animateLimitHitForButton(button: UIButton){
364+ UIView.animateWithDuration(limitHitAnimationDuration) {
365+ button.backgroundColor = self.limitHitAnimationColor
371+extension GMStepper {
372+ func handleTimerFire(timer: NSTimer) {
374+ if timerFireCount % timerFireCountModulo == 0 {
376+ if let button = timer.userInfo as? UIButton {
377+ if button == leftButton {
387+ func scheduleTimerWithUserInfo(userInfo: AnyObject?) {
388+ timer = NSTimer.scheduledTimerWithTimeInterval(timerInterval, target: self, selector: "handleTimerFire:", userInfo: userInfo, repeats: true)
392+ if let timer = timer {