Reputation: 736
I'm in swift 3 and I have a class that's a subclass of UIScrollView. Here it is:
import SpriteKit
/// Scroll direction
enum ScrollDirection {
case vertical
case horizontal
}
class CustomScrollView: UIScrollView {
// MARK: - Static Properties
/// Touches allowed
static var disabledTouches = false
/// Scroll view
private static var scrollView: UIScrollView!
// MARK: - Properties
/// Current scene
private let currentScene: SKScene
/// Moveable node
private let moveableNode: SKNode
/// Scroll direction
private let scrollDirection: ScrollDirection
/// Touched nodes
private var nodesTouched = [AnyObject]()
// MARK: - Init
init(frame: CGRect, scene: SKScene, moveableNode: SKNode, scrollDirection: ScrollDirection) {
self.currentScene = scene
self.moveableNode = moveableNode
self.scrollDirection = scrollDirection
super.init(frame: frame)
CustomScrollView.scrollView = self
self.frame = frame
delegate = self
indicatorStyle = .white
isScrollEnabled = true
isUserInteractionEnabled = true
//canCancelContentTouches = false
//self.minimumZoomScale = 1
//self.maximumZoomScale = 3
if scrollDirection == .horizontal {
let flip = CGAffineTransform(scaleX: -1,y: -1)
transform = flip
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/// Began
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("begin " + String(CustomScrollView.disabledTouches))
for touch in touches {
let location = touch.location(in: currentScene)
guard !CustomScrollView.disabledTouches else { return }
/// Call touches began in current scene
currentScene.touchesBegan(touches, with: event)
/// Call touches began in all touched nodes in the current scene
nodesTouched = currentScene.nodes(at: location)
for node in nodesTouched {
node.touchesBegan(touches, with: event)
}
}
}
/// Moved
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("moved " + String(CustomScrollView.disabledTouches))
for touch in touches {
let location = touch.location(in: currentScene)
guard !CustomScrollView.disabledTouches else { return }
/// Call touches moved in current scene
currentScene.touchesMoved(touches, with: event)
/// Call touches moved in all touched nodes in the current scene
nodesTouched = currentScene.nodes(at: location)
for node in nodesTouched {
node.touchesMoved(touches, with: event)
}
}
}
/// Ended
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: currentScene)
guard !CustomScrollView.disabledTouches else { return }
/// Call touches ended in current scene
currentScene.touchesEnded(touches, with: event)
/// Call touches ended in all touched nodes in the current scene
nodesTouched = currentScene.nodes(at: location)
for node in nodesTouched {
node.touchesEnded(touches, with: event)
}
}
}
/// Cancelled
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("cancelled " + String(CustomScrollView.disabledTouches))
for touch in touches {
let location = touch.location(in: currentScene)
guard !CustomScrollView.disabledTouches else { return }
/// Call touches cancelled in current scene
currentScene.touchesCancelled(touches, with: event)
/// Call touches cancelled in all touched nodes in the current scene
nodesTouched = currentScene.nodes(at: location)
for node in nodesTouched {
node.touchesCancelled(touches, with: event)
}
}
}
}
// MARK: - Touch Controls
extension CustomScrollView {
/// Disable
class func disable() {
CustomScrollView.scrollView?.isUserInteractionEnabled = false
CustomScrollView.disabledTouches = true
}
/// Enable
class func enable() {
CustomScrollView.scrollView?.isUserInteractionEnabled = true
CustomScrollView.disabledTouches = false
}
}
// MARK: - Delegates
extension CustomScrollView: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollDirection == .horizontal {
moveableNode.position.x = scrollView.contentOffset.x
} else {
moveableNode.position.y = scrollView.contentOffset.y
}
}
}
It's main function is to create a scrollable menu, and for the most part it works. I create an object of it in GameScene, and how it's supposed to work is that when a touch is registered, the overridden touch functions (touchBegan, touchMoved, etc.) in CustomScrollView are called, which then call the touch functions in GameScene. This does happen, the menu scrolls fine, and GameScene's methods ARE called.
The catch is my overridden functions (and GameScene's) are only called when you're swiping horizontally. When you swipe up or down (past a certain degree), the menu still scrolls but I think that it's UIScrollView's touch methods that are being called.
When you swipe vertically, my touchCancelled method gets called, which makes me think this has something to do with UIScrollView's gesture recognizers (the pan/drag recognizer I think) firing when they shouldn't be.
Is this the case? If so, can I disable the recognizer? And if I can, should I? On a side note, is this the best (or at least an acceptable) way to implement UIScrollView so that GameScene's touch methods are still called?
Upvotes: 1
Views: 1259
Reputation: 323
If the conflicting gesture recognizers need to be recognized simultaneously, you can make use of gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:),
Upvotes: 2