【问题标题】:Swift SKSpritenodes in a UIScrollViewUIScrollView 中的 Swift SKSpritenodes
【发布时间】:2016-10-04 21:38:59
【问题描述】:

好的,我正在尝试将 SKSpriteNode 添加到 UIScrollView,我该怎么做?

【问题讨论】:

标签: swift uiscrollview sprite-kit skspritenode


【解决方案1】:

到目前为止,您尝试过什么? 作为一般堆栈溢出规则,如果您需要帮助,您应该始终发布代码。

我建议始终从我的 gitHub 项目中获取此代码的最新版本,以防我在此答案后进行了更改,链接在底部。

第 1 步:创建一个新的 swift 文件并粘贴此代码

import SpriteKit

/// Scroll direction
enum ScrollDirection {
    case vertical // cases start with small letters as I am following Swift 3 guildlines.
    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) {
    self.currentScene = scene
    self.moveableNode = moveableNode
    self.scrollDirection = scrollDirection
    super.init(frame: frame)

    CustomScrollView.scrollView = self
    self.frame = frame
    delegate = self
    indicatorStyle = .White
    scrollEnabled = true
    userInteractionEnabled = true
    //canCancelContentTouches = false
    //self.minimumZoomScale = 1
    //self.maximumZoomScale = 3

    if scrollDirection == .horizontal {
        let flip = CGAffineTransformMakeScale(-1,-1)
        transform = flip
    }
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
   }
}

// MARK: - Touches
extension CustomScrollView {

/// Began
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches began in current scene
        currentScene.touchesBegan(touches, withEvent: event)

        /// Call touches began in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesBegan(touches, withEvent: event)
        }
    }
}

/// Moved
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches moved in current scene
        currentScene.touchesMoved(touches, withEvent: event)

        /// Call touches moved in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesMoved(touches, withEvent: event)
        }
    }
}

/// Ended
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches ended in current scene
        currentScene.touchesEnded(touches, withEvent: event)

        /// Call touches ended in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesEnded(touches, withEvent: event)
        }
    }
}

/// Cancelled
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {

    for touch in touches! {
        let location = touch.locationInNode(currentScene)

        guard !CustomScrollView.disabledTouches else { return }

        /// Call touches cancelled in current scene
        currentScene.touchesCancelled(touches, withEvent: event)

        /// Call touches cancelled in all touched nodes in the current scene
        nodesTouched = currentScene.nodesAtPoint(location)
        for node in nodesTouched {
            node.touchesCancelled(touches, withEvent: event)
        }
     }
   }
}

// MARK: - Touch Controls
extension CustomScrollView {

     /// Disable
    class func disable() {
        CustomScrollView.scrollView?.userInteractionEnabled = false
        CustomScrollView.disabledTouches = true
    }

    /// Enable
    class func enable() {
        CustomScrollView.scrollView?.userInteractionEnabled = 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
        }
    }
}

这将创建一个 UIScrollView 的子类并设置它的基本属性。它有自己的 touches 方法,可以传递到相关场景。

步骤 2:在您想要使用它的相关场景中,您创建一个滚动视图和可移动节点属性,如下所示

weak var scrollView: CustomScrollView!
let moveableNode = SKNode()

并在 didMoveToView 中将它们添加到场景中

scrollView = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNode, scrollDirection: .vertical)
scrollView.contentSize = CGSizeMake(self.frame.size.width, self.frame.size.height * 2)
view?.addSubview(scrollView) 


addChild(moveableNode)

您在第 1 行中所做的是使用场景尺寸初始化滚动视图助手。您还可以传递场景以供参考以及在步骤 2 中创建的 moveableNode。 第 2 行是您设置滚动视图的内容大小的地方,在这种情况下,它是屏幕高度的两倍。

Step3: - 添加标签或节点等并定位它们。

label1.position.y = CGRectGetMidY(self.frame) - self.frame.size.height
moveableNode.addChild(label1)

在本例中,标签将位于滚动视图的第二页。这是您必须使用标签和定位的地方。

如果您在滚动视图中有很多页面和很多标签,我建议您执行以下操作。为滚动视图中的每个页面创建一个 SKSpriteNode,并使每个页面的大小与屏幕相同。将它们称为 page1Node、page2Node 等。您可以将第二页上的所有标签添加到 page2Node。这里的好处是您基本上可以像往常一样将所有内容放置在 page2Node 中,而不仅仅是将 page2Node 放置在 scrollView 中。

你也很幸运,因为垂直使用滚动视图(你说你想要的)你不需要做任何翻转和反向定位。

我做了一些类函数,所以如果你需要禁用你的滚动视图,以防你在滚动视图上覆盖另一个菜单。

CustomScrollView.enable()
CustomScrollView.disable()

最后不要忘记在转换到新场景之前从场景中移除滚动视图。在 spritekit 中处理 UIKit 时的痛苦之一。

scrollView?.removeFromSuperView()

How to create a vertical scrolling menu in spritekit?

https://github.com/crashoverride777/SwiftySKScrollView

【讨论】:

  • 最好包括一些例子来展示你的类应该如何使用。大多数时候,像这样的答案(仅限链接的答案)会被标记并删除。
  • 我知道,但这是一个非常广泛的问题,而不是关于特定代码的问题。示例代码会很长
  • 建议使用源代码,但代码不必总是发布,只要问题是针对不会导致笼统答案的特定问题。这个问题就是一个很好的例子。 OP有一个具体问题,即:如何将SKSpriteNode添加到UIScrollView?只有几种方法可以回答这个问题,
  • 是的,但是这几个方法很长,我可以发布一些代码,但它会像一页一样长。
【解决方案2】:

您遇到了一个我一直在努力解决的问题。根本问题是您不能将 SKNodes 添加到 UIKit 视图,也不能将 UIKit 视图添加到 SKNodes。视图不是节点,节点也不是视图,遗憾的是这不起作用。虽然您可以将 UIKit 元素添加到 SKScene 的 view 属性,但这是您可以接受的。在我终于得到它之前,我挣扎了很长一段时间。

顺便说一句,我仍然混合使用 UIKit 和 SpriteKit,但我这样做的方式有限,它从不依赖于向视图添加节点,反之亦然。

最好的办法是创建一个与您需要的一样大的 SKNode 来容纳所有 SKSpriteNode,然后在 touchesMoved: 函数期间调整其在屏幕上的位置。 (本质上是创建您自己的基于 SpriteKit 的滚动视图)。

【讨论】:

    【解决方案3】:

    您可以使用SKCameraNode 和比您的视口更大的场景。这基本上是 SpriteKit 版本的滚动视图。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多