SpriteKit, Swift 2.0 - ScrollView in reverse

2019-03-02 02:43发布

问题:

I managed to get a scrollview working and scrolling, but now when I go to scroll it only scrolls from right to left and was wondering how I go about reversing it so it scrolls from left to right instead.

Here is my menu code that contains my scrollview:

var moveableNode = SKNode()
var scrollView: CustomScrollView!

private var spriteSize = CGSize.zero

let kMargin: CGFloat = 40

var sprite = SKSpriteNode()

class Menu: SKScene {


override func didMoveToView(view: SKView) {


    addChild(moveableNode)

    spriteSize = SKSpriteNode (imageNamed: "card_level01").size

    let initialMargin = size.width/2
    let marginPerImage = kMargin + spriteSize.width

    scrollView = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNode)

    scrollView.contentSize = CGSizeMake(initialMargin*2 + (marginPerImage * 7), size.height)

    // scrollView.contentSize = CGSizeMake(self.frame.size.width * 2, self.frame.size.height)
    view.addSubview(scrollView)


    for i in 1...8 {

        let sprite = SKSpriteNode(imageNamed: String(format: "card_level%02d", i))
        sprite.position = CGPoint (x: initialMargin + (marginPerImage * (CGFloat(i) - 1)), y: size.height / 2)
        moveableNode.addChild(sprite)

    }

Here is my scrollView Class that is a subclass of UIScrollView:

 var nodesTouched: [AnyObject] = [] // global

class CustomScrollView: UIScrollView {

// MARK: - Static Properties

/// Touches allowed
static var disabledTouches = false

/// Scroll view
private static var scrollView: UIScrollView!

private static var contentView: UIView!
// MARK: - Properties

/// Current scene
private var currentScene: SKScene?

/// Moveable node
private var moveableNode: SKNode?

// MARK: - Init
init(frame: CGRect, scene: SKScene, moveableNode: SKNode) {
    print("Scroll View init")
    super.init(frame: frame)

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

    //flip for spritekit (only needed for horizontal)
    let verticalFlip = CGAffineTransformMakeScale(-1,-1)
    self.transform = verticalFlip

}

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?) {
    print("Touch began scroll view")

    guard !CustomScrollView.disabledTouches else { return }
    currentScene?.touchesBegan(touches, withEvent: event)
    }

/// moved
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    print("Touch moved scroll view")

    guard !CustomScrollView.disabledTouches else { return }
    currentScene?.touchesMoved(touches, withEvent: event)
}

/// ended
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    print("Touch ended scroll view")

    guard !CustomScrollView.disabledTouches else { return }
    currentScene?.touchesEnded(touches, withEvent: event)
}

/// cancelled
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
    print("Touch cancelled scroll view")

    guard !CustomScrollView.disabledTouches else { return }
    currentScene?.touchesCancelled(touches, withEvent: event)
   }
 }

 // MARK: - Touch Controls
extension CustomScrollView {

/// Disable
class func disable() {
    print("Disabled scroll view")
    CustomScrollView.scrollView?.userInteractionEnabled = false
    CustomScrollView.disabledTouches = true
}

/// Enable
class func enable() {
    print("Enabled scroll view")
    CustomScrollView.scrollView?.userInteractionEnabled = true
    CustomScrollView.disabledTouches = false
  }
}

// MARK: - Delegates
extension CustomScrollView: UIScrollViewDelegate {

/// did scroll
func scrollViewDidScroll(scrollView: UIScrollView) {
    print("Scroll view did scroll")

   moveableNode!.position.x = scrollView.contentOffset.x // Left/Right

   //moveableNode!.position.y = scrollView.contentOffset.y // Up/Dowm
   }


}

回答1:

You need get my updated helper on gitHub (v1.1) first before reading the rest.

My helper only really works well when your scene scale mode (gameViewController) is set to

.ResizeFill

so your scenes do not crop. If you use a different scaleMode such as

.AspectFill 

than it might crop stuff in your scrollView which you would need to adjust for.

It also doesnt work if your game/app supports both portrait and landscape, which is unlikely for a game anyway.

So as I said and you have also noticed when using a ScrollView in spriteKit the coordinates are different compared to UIKit. For vertical scrolling this doesn't really mean anything, but for horizontal scrolling everything it is in reverse. So to fix this you do the following

Set up your scrollView for horizontal scrolling, passing along the new scrollDirection property (.Horizontal in this case)

scrollView = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNode, scrollDirection: .Horizontal)
scrollView.contentSize = CGSizeMake(self.frame.size.width * 3, self.frame.size.height) // * 3 makes it twice as wide as screen
view.addSubview(scrollView)

you need to also add this line of code after adding it to the view.

scrollView.setContentOffset(CGPoint(x: 0 + self.frame.size.width * 2, y: 0), animated: true)

this is the line you use to tell the ScrollView on which page to start. Now in this example the scrollView is three times as wide as the screen, therefore you need to offset the content by 2 screen lengths

Now to make things easier for positioning I would do this, create sprites for each page of the scrollView. This makes positioning much easier later on.

let page1ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(self.frame.size.width, self.frame.size.height))
page1ScrollView.position = CGPointMake(CGRectGetMidX(self.frame) - (self.frame.size.width * 2), CGRectGetMidY(self.frame))
moveableNode.addChild(page1ScrollView)

let page2ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(self.frame.size.width, self.frame.size.height))
page2ScrollView.position = CGPointMake(CGRectGetMidX(self.frame) - (self.frame.size.width), CGRectGetMidY(self.frame))
moveableNode.addChild(page2ScrollView)

let page3ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(self.frame.size.width, self.frame.size.height))
page3ScrollView.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
moveableNode.addChild(page3ScrollView)

and now you can positioning your actual labels, sprites much easier.

/// Test label page 1
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = "Hello, World!"
myLabel.fontSize = 45
myLabel.position = CGPointMake(0, 0)
page1ScrollView.addChild(myLabel)

/// Test sprite page 2
let sprite = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 50, height: 50))
sprite.position = CGPointMake(0, 0)
page2ScrollView.addChild(sprite)

/// Test sprite page 3
let sprite2 = SKSpriteNode(color: SKColor.blueColor(), size: CGSize(width: 50, height: 50))
sprite2.position = CGPointMake(0, 0)
page3ScrollView.addChild(sprite2)

Hope this helps.

I also updated my GitHub project to explain this better

https://github.com/crashoverride777/Swift2-SpriteKit-UIScrollView-Helper