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

Posted

技术标签:

【中文标题】Swift 3:UIScrollView 和(禁用)手势识别器【英文标题】:Swift 3: UIScrollView and (disabling) Gesture Recognizers 【发布时间】:2016-11-27 20:27:48 【问题描述】:

我在 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】:

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

【讨论】:

以上是关于Swift 3:UIScrollView 和(禁用)手势识别器的主要内容,如果未能解决你的问题,请参考以下文章

Swift 3 - UITableView 在 UIScrollView 中被切断

快速禁用 UIScrollView 中的垂直滚动?

swift 3中的错误UIScrollView

Swift 3 - 如何在 .xib 文件上为 UIScrollView 分配委托?

无法使用 UIScrollView 和 pagingEnabled=YES 禁用反弹

UIViewcontroller 不加载子视图(swift 3)