Skip to content

Commit 5514679

Browse files
committed
Generate haptic feedback when the ends of the slider are reached
1 parent 9a5bac5 commit 5514679

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ To run the example project, clone the repo, and run `pod install` from the Examp
1111

1212
## Requirements
1313

14-
iOS 8.0+
14+
iOS 8.0+ (iOS 10.0+ required for haptic feedback)
1515

1616
## Installation
1717

TactileSlider/Classes/TactileSlider.swift

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,29 @@ import UIKit
110110

111111
private let renderer = TactileSliderLayerRenderer()
112112

113+
// gross workaround for not being able to use @available on stored properties, from https://www.klundberg.com/blog/Swift-2-and-@available-properties/
114+
private var _minMaxFeedbackGenerator: AnyObject?
115+
@available(iOS 10.0, *) private var minMaxFeedbackGenerator: UIImpactFeedbackGenerator? {
116+
get {
117+
return _minMaxFeedbackGenerator as? UIImpactFeedbackGenerator
118+
}
119+
set(newValue) {
120+
_minMaxFeedbackGenerator = newValue
121+
}
122+
}
123+
124+
private var _feedbackStyle: Int?
125+
@available(iOS 10.0, *) open var feedbackStyle: UIImpactFeedbackGenerator.FeedbackStyle {
126+
get {
127+
guard let _feedbackStyle = _feedbackStyle,
128+
let style = UIImpactFeedbackGenerator.FeedbackStyle(rawValue: _feedbackStyle) else { return .light }
129+
return style
130+
}
131+
set(newValue) {
132+
_feedbackStyle = newValue.rawValue
133+
}
134+
}
135+
113136

114137
// MARK: - Initialization
115138

@@ -146,6 +169,10 @@ import UIKit
146169
renderer.trackLayer.addSublayer(renderer.thumbLayer)
147170

148171
updateLayerFrames()
172+
173+
if #available(iOS 10.0, *) {
174+
feedbackStyle = .light
175+
}
149176
}
150177

151178
open func setValue(_ newValue: Float, animated: Bool) {
@@ -194,9 +221,28 @@ import UIKit
194221
} else if value == maximum && valueChange > 0 {
195222
// already hit maximum, don't change the value
196223
} else {
224+
197225
let newValue = value + valueChange
198226
setValue(newValue, animated: false)
199227

228+
// control feedback generator according to state
229+
if #available(iOS 10.0, *) {
230+
switch sender.state {
231+
case .began:
232+
minMaxFeedbackGenerator = UIImpactFeedbackGenerator(style: feedbackStyle)
233+
minMaxFeedbackGenerator?.prepare()
234+
case .changed:
235+
if newValue != value {
236+
minMaxFeedbackGenerator?.impactOccurred()
237+
minMaxFeedbackGenerator?.prepare()
238+
}
239+
case .cancelled, .ended, .failed:
240+
_minMaxFeedbackGenerator = nil
241+
default:
242+
break
243+
}
244+
}
245+
200246
let remainingTranslationAmount: CGFloat
201247
if value == newValue {
202248
remainingTranslationAmount = 0
@@ -211,7 +257,7 @@ import UIKit
211257
sendActions(for: .valueChanged)
212258
}
213259

214-
if sender.state != .ended && sender.state != .cancelled {
260+
if sender.state != .ended && sender.state != .cancelled && sender.state != .failed {
215261
renderer.popUp = scaleUpWhenInUse
216262
} else {
217263
renderer.popUp = false

0 commit comments

Comments
 (0)