Skip to content

Commit 3ce52db

Browse files
committed
Improve tap handling; add capability to handle scrolling from pointer devices
1 parent 33d6bba commit 3ce52db

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

Example/TactileSlider/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
<array>
3131
<string>armv7</string>
3232
</array>
33+
<key>UIApplicationSupportsIndirectInputEvents</key>
34+
<true/>
3335
<key>UISupportedInterfaceOrientations</key>
3436
<array>
3537
<string>UIInterfaceOrientationPortrait</string>

TactileSlider/Classes/TactileSlider.swift

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,43 @@ import UIKit
7878

7979
/// If true, a single tap anywhere in the slider will set it to that value
8080
///
81-
/// - Remark: Users may accidentally activate this feature while trying to make very small adjustments. If the intended use case involves making very small adjustments with the slider, consider disabling this feature.
82-
@IBInspectable open var enableTapping: Bool = true
81+
/// On iOS 9 or later, direct taps or indirect (trackpad or mouse) clicks can be specified using the `allowedTapTypes` property.
82+
///
83+
/// - Remark: Users may accidentally activate this feature while trying to make very small adjustments. If the intended use case involves making very small, precise adjustments with the slider, consider disabling this feature or restricting it to indirect touches only using `allowedTapTypes`.
84+
@IBInspectable open var enableTapping: Bool = true {
85+
didSet {
86+
setTapEnabled()
87+
}
88+
}
89+
90+
/// An array of `UITouch.TouchType`s used to distinguish the type of touches for the `enableTapping` feature.
91+
///
92+
/// This is a wrapper around the [UITapGestureRecognizer](https://developer.apple.com/documentation/uikit/uigesturerecognizer)'s [allowedTouchTypes](https://developer.apple.com/documentation/uikit/uigesturerecognizer/1624223-allowedtouchtypes) property.
93+
///
94+
/// If `enableTapping` is `true`, this can be used to filter direct (e.g. finger) or indirect (e.g. trackpad) touches.
95+
///
96+
/// - Requires: iOS 9
97+
/// - Requires: `enableTapping == true`, otherwise no effect
98+
@available(iOS 9.0, *)
99+
open var allowedTapTypes: [NSNumber] {
100+
get {
101+
return tapGestureRecognizer.allowedTouchTypes
102+
}
103+
set(newAllowedTapTypes) {
104+
tapGestureRecognizer.allowedTouchTypes = newAllowedTapTypes
105+
}
106+
}
107+
108+
/// If true, the slider can be adjusted by scrolling with a pointing device (e.g. two-finger scrolling with a trackpad or scrolling a mouse wheel).
109+
///
110+
/// - Requires: iOS 13.4
111+
@IBInspectable open var isScrollingEnabled: Bool = true {
112+
didSet {
113+
if #available(iOS 13.4, *) {
114+
setScrollingEnabled()
115+
}
116+
}
117+
}
83118

84119
/// If true, the slider will animate its scale when it is being dragged
85120
@IBInspectable open var scaleUpWhenInUse: Bool = false
@@ -143,6 +178,9 @@ import UIKit
143178

144179
private let renderer = TactileSliderLayerRenderer()
145180

181+
private var dragGestureRecognizer: UIPanGestureRecognizer!
182+
private var tapGestureRecognizer: UITapGestureRecognizer!
183+
146184
// gross workaround for not being able to use @available on stored properties, from https://www.klundberg.com/blog/Swift-2-and-@available-properties/
147185
private var _minMaxFeedbackGenerator: AnyObject?
148186
@available(iOS 10.0, *) private var minMaxFeedbackGenerator: UIImpactFeedbackGenerator? {
@@ -189,16 +227,21 @@ import UIKit
189227
isAccessibilityElement = true
190228
accessibilityTraits.insert(UIAccessibilityTraits.adjustable)
191229

192-
let dragGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didPan))
230+
dragGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didPan))
193231
dragGestureRecognizer.cancelsTouchesInView = false
194232
addGestureRecognizer(dragGestureRecognizer)
195233

196-
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTap))
234+
tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTap))
197235
tapGestureRecognizer.numberOfTapsRequired = 1
198236
tapGestureRecognizer.numberOfTouchesRequired = 1
199237
tapGestureRecognizer.cancelsTouchesInView = false
200238
addGestureRecognizer(tapGestureRecognizer)
201239

240+
setTapEnabled()
241+
if #available(iOS 13.4, *) {
242+
setScrollingEnabled()
243+
}
244+
202245
renderer.tactileSlider = self
203246
renderer.cornerRadius = cornerRadius
204247
traitCollectionDidChange(nil)
@@ -257,6 +300,19 @@ import UIKit
257300

258301
// MARK: - gesture handling
259302

303+
private func setTapEnabled() {
304+
tapGestureRecognizer.isEnabled = enableTapping
305+
}
306+
307+
@available(iOS 13.4, *)
308+
private func setScrollingEnabled() {
309+
if isScrollingEnabled {
310+
dragGestureRecognizer.allowedScrollTypesMask = UIScrollTypeMask.all
311+
} else {
312+
dragGestureRecognizer.allowedScrollTypesMask = []
313+
}
314+
}
315+
260316
@objc func didPan(sender: UIPanGestureRecognizer) {
261317
let translation = sender.translation(in: self)
262318
let valueChange = valueChangeForTranslation(translation)
@@ -311,8 +367,6 @@ import UIKit
311367
}
312368

313369
@objc func didTap(sender: UITapGestureRecognizer) {
314-
guard enableTapping else { return }
315-
316370
if sender.state == .ended {
317371
let tapLocation: CGFloat
318372
if (reverseValueAxis && !vertical) || (!reverseValueAxis && vertical) {

0 commit comments

Comments
 (0)