-
XPhoenix
-
http://www.xcombinator.com Nate Murray
-
XPhoenix
-
Corey Sayers
-
http://www.firstpixel.com Gil Beyruth
-
Prashant
-
Aeshvarya Verma
-
Aeshvarya Verma
-
Aeshvarya Verma
-
http://Brandonreynolds.com Brandon Reynolds
-
Federico
-
Andrea
-
http://www.optimates.se Tommy Safstrom
-
http://tonyngo.net/2011/11/scrolling-ccnode-in-cocos2d/ Scrolling CCNode in Cocos2d | Tony Ngo
-
Borfmaker
-
Hugo
-
Seamus Cranley

A Paging UIScrollView in Cocos2d (with previews)
I’ve created a sample project that shows how to do a paged
UIScrollViewwithin Cocos2d. Here’s a video showing the effect:You can find the code on github
My solution’s main ideas are adapted from these two pages:
My contribution is combining the
UIScrollViewwith previews with Cocos2d and cleaning it up.If you haven’t tried to implement this before it might not be obvious why this is tricky to implement. Apple’s
UIScrollViewallows you to have a view which scrolls and optionally snaps to pages. The effect you see in the video above (and in Angry Birds level selection and many other apps) shows a preview of each panel on either side. This let’s you easily see if a next or previous page exists and you see a preview of that page.The problem is that Apple’s
UIScrollViewdoesn’t let you set the width of the frame, so you can’t page less than a whole screen (well, a whole width of theUIScrollView, more on that later).To get around this I originally tried writing my own paging controller. If you’ve tried this you’ll know that it is extremely tricky to get the same interaction dynamics as Apple’s. (For instance, pull out your phone and play with the Photo application. Notice if you just drag slowly you lack enough inertia to go to the next page so it will snap back to the frame your are on. If you flick fast over a small area the page will skip to the next frame. Etc.) While at first glance the rules seem easy to reimplement, you have to cover a lot of edge cases to recreating the familiar paging interaction.
So ideally we need to figure out a way to use Apple’s
UIScrollViewand we should save ourselves a lot of work.Like we said above, a
UIScrollViewwill only page the width of the entireUIScrollView. So to get this preview effect you can create aUIScrollViewthat is less than the width of the entire screen. The problem here is that any touches that lie outside of thatUIScrollView(say on the edge of the screen won’t be sent to theUIScrollView.Our solution, (again, borrowed largely from the above links) looks like this:
The idea is this:
CCMenuand add it to aCCLayerUIScrollViewis resized to the width of our panel images (smaller than the whole screen)UIScrollViewtransforms its scrolling action into moving the position of theCCLayercontaining ourCCMenuTouchDelegatingViewthat simply forwards its touches on to theUIScrollViewMore Details
In Jacob’s Shapes (JS), we have a
GameControllerwhich knows all of the levels. For the sake of this example, we’re just going to store all the level names in anNSArray.Custom CCMenu and CCMenuItem
We use a custom subclass of
CCMenuandCCMenuItem,NMPanelMenuandNMPanelMenuItem, respectively.NMPanelMenutweaks how the current item is determined. OverridingNMPanelMenuItemallows us to add metadata about the panel, play sounds, and optimize how we use the images for selected panels.Here we used
CCSprite#spriteWithFile, but in JS we use Zwoptex-created sprite sheets for the panels and then create sprites from those frames. This makes a huge difference in the load time of this scene when you have 20 panels. In JS, instead of loading 20 textures (one for each panel) we only load 2 textures, each containing 10 panels each.JS is graphics heavy and we definitely had to pay attention to file sizes to keep it under 22MB. Originally I had created two versions of each panel, one for “off” and one with a glow for “on” (active/selected). Each of the panels as a transparent png was somewhere around 100k. So 100k x 2 for each state x 20 panels was somewhere around 4MB just for this single scene.
We decided to sacrifice a bit of the quality of the glow for the “on” state and just create one transparent image for the glow and reuse that for every panel.
To use the glow a portion of our
NMPanelMenuItemlooks like this:Where
self.glowis aCCSpriteattached to theNMPanelMenuItem.Adding the Cocos2d Panels
Next we need to setup some basic options for how much padding we want and what the total width of the panels layer is going to be. Then we add the panels to our scene and set the position.
Note that the panels are the visual representation but we haven’t added in any scrolling dynamics. To do that we need to add a
UIScrollView.Adding the UIScrollView
Here we do two things:
CocosOverlayScrollViewwhich is only one panel wide (less than the whole screen). If we had this layer only then we wouldn’t be notified of touches on the edge of the screen.We add the
TouchDelegatingViewwhich is full screen. TheTouchDelegatingViewwill delegate any touches it receives to our paging scroll viewYou can configure your
UIScrollViewoptions by simply changing the code inCocosOverlayScrollView#initWithFrame:numPages:width:layer. (Note that this class was originally written by Alexander Repty)The
TouchDelegatingViewsimply delegates any touches it receives to theCocosOverlayScrollView.And there you have it! Feel free to fork and make any changes to the code and send me a pull request.
What do you think? Have any ideas for cleaning it up? Leave your comments below!