Swift 3:UIScrollView和(禁用)手势识别器

时间:2016-11-27 20:27:48

标签: ios swift cocoa-touch uiscrollview uigesturerecognizer

我在swift 3中,我有一个类,它是UIScrollView的子类。这是:

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
        }
    }
}

它的主要功能是创建一个可滚动的菜单,并且大多数情况下它都有效。我在GameScene中创建了它的一个对象,它应该如何工作,当注册触摸时,调用CustomScrollView中被覆盖的触摸函数(touchBegan,touchMoved等),然后调用GameScene中的触摸函数。这确实发生了,菜单滚动得很好,GameScene的方法被调用。

捕获是我的重写函数(和GameScene的)仅在您水平滑动时调用。当您向上或向下滑动(超过一定程度)时,菜单仍会滚动,但我认为这是UIScrollView的触控方法。

当你垂直滑动时,我的touchCancelled方法被调用,这让我觉得这与UIScrollView的手势识别器(我认为是平移/拖动识别器)在它们不应该被触发时有关。

是这样的吗?如果是这样,我可以禁用识别器吗?如果可以的话,我应该吗?另外,这是实现UIScrollView的最佳(或至少是可接受的)方式,以便仍然可以调用GameScene的触摸方法吗?

1 个答案:

答案 0 :(得分:2)

如果需要同时识别冲突的手势识别器,您可以使用gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)