Hi I currently have a horizontal UIScrollView
that allows me to pick a character in my game and then select it but the problem that I have now is I am trying to get the scrollview to stop at the point where the sprite/character is in the middle of the screen and instead of having it stop anywhere.
My UIScrollView
has a “moveable node” that contains multiple pages that hold all the sprites as seen below:
scrollViewHorizontal = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNodeHorizontal, scrollDirection: .Horizontal)
scrollViewHorizontal.contentSize = CGSizeMake(self.frame.size.width * 4, self.frame.size.height) // * 4 makes it three times as wide as screen
view?.addSubview(scrollViewHorizontal)
scrollViewHorizontal.hidden = true
addChild(moveableNodeHorizontal)
moveableNodeHorizontal.hidden = true
moveableNodeHorizontal.zPosition = 100000
scrollViewHorizontal.setContentOffset(CGPoint(x: 0 + self.frame.size.width + self.frame.size.width * 2, y: 0), animated: false)
let page1ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(scrollViewHorizontal.frame.size.width, scrollViewHorizontal.frame.size.height))
page1ScrollView.zPosition = -1
page1ScrollView.position = CGPointMake(CGRectGetMidX(self.frame) - (self.frame.size.width * 3.5), CGRectGetMidY(self.frame) - (self.frame.height / 2))
moveableNodeHorizontal.addChild(page1ScrollView)
let page2ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(scrollViewHorizontal.frame.size.width, scrollViewHorizontal.frame.size.height))
page2ScrollView.zPosition = -1
page2ScrollView.position = CGPointMake(CGRectGetMidX(self.frame) - (self.frame.size.width * 2.5), CGRectGetMidY(self.frame) - (self.frame.height / 2))
moveableNodeHorizontal.addChild(page2ScrollView)
Characters.append(generateCharacters(CGPointMake(0, 0), page:(page1ScrollView), tex: "YellowFrog"))
Characters.append(generateCharacters(CGPointMake(100, 0), page:(page1ScrollView), tex: "Frog"))
Characters.append(generateCharacters(CGPointMake(0, 0), page:(page2ScrollView), tex: "ball"))
Characters.append(generateCharacters(CGPointMake(100, 0), page:(page2ScrollView), tex: "ball"))
I searched this previously before asking the question and it was recommended that I use this:
func scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
But I have no idea how to implement it into my code because my scrollview is contained in another class which can be seen here:
/// Nodes touched
var nodesTouched: [AnyObject] = [] // global
/// Scroll direction
enum ScrollDirection: Int {
case None = 0
case Vertical
case Horizontal
}
/// Custom UIScrollView class
class CustomScrollView: UIScrollView {
// MARK: - Static Properties
/// Touches allowed
static var disabledTouches = false
/// Scroll view
private static var scrollView: UIScrollView!
// MARK: - Properties
/// Nodes touched. This will forward touches to node subclasses.
private var nodesTouched = [AnyObject]()
/// Current scene
private let currentScene: SKScene
/// Moveable node
private let moveableNode: SKNode
/// Scroll direction
private let scrollDirection: ScrollDirection
// 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
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?) {
//super.touchesBegan(touches, withEvent: event)
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?) {
//super.touchesMoved(touches, withEvent: event)
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?) {
//super.touchesEnded(touches, withEvent: event)
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?) {
//super.touchesCancelled(touches, withEvent: event)
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
}
}
}
EDIT:
extension CustomScrollView: UIScrollViewDelegate {
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollDirection == .Horizontal {
moveableNode.position.x = scrollView.contentOffset.x
} else {
moveableNode.position.y = scrollView.contentOffset.y
}
}
}
CustomScrollView
is a project showed howUIKit
could be used insprite-kit
but this causes a lot of work during rendering that slows your game (due to low fps) so it's advisable and reasonable to use it just only for your game menus, not for the game.A way to iOS8.x:
You can build for example many
SKSpriteNode
backgrounds that follow the one with the other and in yourupdate
method doing:A way to iOS9x:
Apple added the
SKCameraNode
class tosprite-kit
in iOS 9 to make it easier to scroll and zoom insprite-kit
scenes.The
CustomScrollView
page selector.Having said that we come to your situation, suppose you have all your pages in array called
pages
and you want to stop the scroll to the x page:Another good idea it's to intercept the scroll delegate methods to update your elements:
You could obtain your page number whit this code: