RSS

Step by Step: How to build a scroll view by cocos2d

05 Oct

One of the dilemmas that many game engines are facing is whether they should provide many built-in high-level UI gadgets for developers, e.g. scroll view. Some of them feel that game engines should be condense and only focus on providing good gaming-related solutions, like graphics and sounds. However, as developers, we really need some neat UI gadgets for our game. Recently, I was trying to build a vertical scroll view for my iPhone game using cocos2d. Now I’d like share some pains and gains during the process.

Before implementing my own scroll view, I searched on the Internet and found some extension libraries for cocos2d. There is a scroll view for cocos2d, CCScrollLayer. Unfortunately, this gadget is more like a page viewer, not a viewer for a list of items. So I decided to build my own version. Below is a scroll view capture from my game that is under developing. Of course, if you prefer to read the code file directly, you can download it from here. Yet I suggest you to skim this blog to get the general idea of how to implementing scroll view, and it is going to help you understand raw code. 🙂

cocos2d-scrollview

Designing Phase

From CCScrollLayer, I borrowed some design ideas.

1. This gadget is inherited from CCLayer in order to receive touch events.

2. Every item in the list is a sub-layer of scroll view, and we need to pass down touch events to items in the list. Every item is a sub-class of CCLayer, i.e., we can have buttons, images and everything in the item layer.

Implementing Phase

If you want to follow my steps to build a simple scroll view, it is better grabbing some cookies and drinks before starting, we will have a lot of coding work, but most importantly, have fun!

Step 1: Create a scroll view class

Create a scroll view layer class, and write a basic initialization method for use like below.

   1: @interface FGScrollLayer : CCLayer

   2: {

   3:     // Holds pages.

   4:     NSMutableArray *layers_;

   5:

   6:     // Holds current pages width offset.

   7:     CGFloat pagesOffset_;

   8:

   9:     // Holds the height of every page

  10:     CGFloat pageHeight_;

  11:

  12:     // Holds the width of every page

  13:     CGFloat pageWidth_;

  14:

  15:     // Holds the maximum upper position

  16:     CGFloat maxVerticalPos_;

  17:

  18:     // Holds the real responsible rect in the screen

  19:     CGRect realBound;

  20: }

  21:

  22: /** Offset, that can be used to let user see next/previous page. */

  23: @property(readwrite) CGFloat pagesOffset;

  24:

  25: /** Page height, this version requires that each page shares the same height and width */

  26: @property(readonly) CGFloat pageHeight;

  27: @property(readonly) CGFloat pageWidth;

  28:

  29: #pragma mark Init/Creation

  30:

  31: /** Creates new scrollLayer with given pages & width offset.

  32:  * @param layers NSArray of CCLayers, that will be used as pages.

  33:  * @param pageSize indicates the size of every page, now this version requires each page 

  34:  * share the same page size

  35:  * @param widthOffset Length in X-coord, that describes length of possible pages

  36:  * @param visibleRect indicates the real position and size on the screen

  37:  * intersection. */

  38: +(id) nodeWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset: (int) pOffset visibleRect: (CGRect)rect;

  39:

  40: /** Inits scrollLayer with given pages & width offset.

  41:  * @param layers NSArray of CCLayers, that will be used as pages.

  42:  * @param pageSize indicates the size of every page, now this version requires each page

  43:  * share the same page size

  44:  * @param pagesOffset Length in X-coord, that describes length of possible pages

  45:  * @param visibleRect indicates the real position and size on the screen

  46:  * intersection. */

  47: -(id) initWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset: (int) pOffset visibleRect: (CGRect)rect;

  48:

  49: @end

.h file

   1: @implementation FGScrollLayer

   2:

   3: @synthesize pagesOffset = pagesOffset_;

   4: @synthesize pageHeight = pageHeight_;

   5: @synthesize pageWidth = pageWidth_;

   6:

   7: +(id) nodeWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset:(int)pOffset visibleRect:(CGRect)rect{

   8:     return [[[self alloc] initWithLayers: layers pageSize:pageSize pagesOffset:pOffset visibleRect:rect] autorelease];

   9: }

  10:

  11: -(id) initWithLayers:(NSArray *)layers pageSize:(CGSize)pageSize pagesOffset:(int)pOffset visibleRect:(CGRect)rect{

  12:     if ( (self = [super init]) )

  13:     {

  14:         NSAssert([layers count], @"FGScrollLayer#initWithLayers:widthOffset: you must provide at least one layer!");

  15:

  16:         // Enable Touches/Mouse.

  17: #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED

  18:         self.isTouchEnabled = YES;

  19: #endif

  20:

  21:         // Save offset.

  22:         self.pagesOffset = pOffset;

  23:

  24:         // Save array of layers.

  25:         layers_ = [[NSMutableArray alloc] initWithArray:layers copyItems:NO];

  26:

  27:         // Save pages size for later calculation

  28:         pageHeight_ = pageSize.height;

  29:         pageWidth_ = pageSize.width;

  30:         maxVerticalPos_ = pageHeight_ * [layers_ count] - rect.size.height + 5;

  31:

  32:         realBound = rect;

  33:

  34:         [self updatePages];

  35:     }

  36:     return self;

  37: }

  38:

  39: - (void) dealloc

  40: {

  41:     self.delegate = nil;

  42:

  43:     [layers_ release];

  44:     layers_ = nil;

  45:

  46:     [super dealloc];

  47: }

  48:

  49: - (void) updatePages

  50: {

  51:     // Loop through the array and add the screens if needed.

  52:     int i = 0;

  53:     for (CCLayer *l in layers_)

  54:     {

  55:         l.position = ccp(realBound.origin.x,  realBound.origin.y + (realBound.size.height - i * (pageHeight_ - self.pagesOffset)));

  56:         if (!l.parent)

  57:             [self addChild:l];

  58:         i++;

  59:     }

  60: }

.m file

Note: the realBound variable indicates the real position and size of the scroll view in the screen. And in the method updatePages, we calculate the real position for each item according to the realBound. So here we can simply leave scroll view layer with default position(0,0).

Step 2: Write the touch handler

   1: @protocol FGScrollLayerDelegate

   2:

   3: @optional

   4:

   5: /** Called when scroll layer begins scrolling.

   6:  * Usefull to cancel CCTouchDispatcher standardDelegates.

   7:  */

   8: - (void) scrollLayerScrollingStarted:(FGScrollLayer *) sender;

   9:

  10: /** Called at the end of moveToPage:

  11:  */

  12: - (void) scrollLayer: (FGScrollLayer *) sender scrolledToPageNumber: (int) page;

  13:

  14: @end

Put above code in the .h file outside of the definition of class FGScrollLayer. We need a delegate to help us handle all touch events. Besides, we need to decide whether we need to steal touch events or sending those events to items to handle.

After defining a delegate, put below code into the definition of class FGScrollLayer.

   1: NSObject <FGScrollLayerDelegate> *delegate_;

   2:

   3: // The screen coord of initial point the user starts their swipe.

   4: CGFloat startSwipe_;

   5:

   6: // The coord of initial position the user starts theri swipe.

   7: CGFloat startSwipeLayerPos_;

   8:

   9: // For what distance user must slide finger to start scrolling menu.

  10: CGFloat minimumTouchLengthToSlide_;

  11:

  12: // Internal state of scrollLayer (scrolling or idle).

  13: int state_;

  14:

  15: BOOL stealTouches_;

  16:

  17: #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED

  18: // Holds the touch that started the scroll

  19: UITouch *scrollTouch_;

  20: #endif

Also add some properties in the .h file. See below:

   1: @property (readwrite, assign) NSObject <FGScrollLayerDelegate> *delegate;

   2:

   3: #pragma mark Scroll Config Properties

   4:

   5: /** Calibration property. Minimum moving touch length that is enough

   6:  * to cancel menu items and start scrolling a layer.

   7:  */

   8: @property(readwrite, assign) CGFloat minimumTouchLengthToSlide;

   9:

  10: /** If YES - when starting scrolling FGScrollLayer will claim touches, that are

  11:  * already claimed by others targetedTouchDelegates by calling CCTouchDispatcher#touchesCancelled

  12:  * Usefull to have ability to scroll with touch above menus in pages.

  13:  * If NO - scrolling will start, but no touches will be cancelled.

  14:  * Default is YES.

  15:  */

  16: @property(readwrite) BOOL stealTouches;

Now turn to the implementation side. Put those code below into initialization method in the .m file.

   1: self.stealTouches = YES;

   2:

   3: // Set default minimum touch length to scroll.

   4: self.minimumTouchLengthToSlide = 30.0f;

And add several methods to handle touch events.

   1: enum

   2: {

   3:     kFGScrollLayerStateIdle,

   4:     kFGScrollLayerStateSliding,

   5: };

   6:

   7: #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED

   8: @interface CCTouchDispatcher (targetedHandlersGetter)

   9:

  10: - (id<NSFastEnumeration>) targetedHandlers;

  11:

  12: @end

  13:

  14: @implementation CCTouchDispatcher (targetedHandlersGetter)

  15:

  16: - (id<NSFastEnumeration>) targetedHandlers

  17: {

  18:     return targetedHandlers;

  19: }

  20:

  21: @end

  22: #endif

  23: #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED

  24:

  25: /** Register with more priority than CCMenu's but don't swallow touches. */

  26: -(void) registerWithTouchDispatcher

  27: {

  28: #if COCOS2D_VERSION >= 0x00020000

  29:     CCTouchDispatcher *dispatcher = [[CCDirector sharedDirector] touchDispatcher];

  30:     int priority = kCCMenuHandlerPriority - 1;

  31: #else

  32:     CCTouchDispatcher *dispatcher = [CCTouchDispatcher sharedDispatcher];

  33:     int priority = kCCMenuTouchPriority - 1;

  34: #endif

  35:

  36:     [dispatcher addTargetedDelegate:self priority: priority swallowsTouches:NO];

  37: }

  38:

  39: /** Hackish stuff - stole touches from other CCTouchDispatcher targeted delegates.

  40:  Used to claim touch without receiving ccTouchBegan. */

  41: - (void) claimTouch: (UITouch *) aTouch

  42: {

  43: #if COCOS2D_VERSION >= 0x00020000

  44:     CCTouchDispatcher *dispatcher = [[CCDirector sharedDirector] touchDispatcher];

  45: #else

  46:     CCTouchDispatcher *dispatcher = [CCTouchDispatcher sharedDispatcher];

  47: #endif

  48:

  49:     // Enumerate through all targeted handlers.

  50:     for ( CCTargetedTouchHandler *handler in [dispatcher targetedHandlers] )

  51:     {

  52:         // Only our handler should claim the touch.

  53:         if (handler.delegate == self)

  54:         {

  55:             if (![handler.claimedTouches containsObject: aTouch])

  56:             {

  57:                 [handler.claimedTouches addObject: aTouch];

  58:             }

  59:         }

  60:         else

  61:         {

  62:             // Steal touch from other targeted delegates, if they claimed it.

  63:             if ([handler.claimedTouches containsObject: aTouch])

  64:             {

  65:                 if ([handler.delegate respondsToSelector:@selector(ccTouchCancelled:withEvent:)])

  66:                 {

  67:                     [handler.delegate ccTouchCancelled: aTouch withEvent: nil];

  68:                 }

  69:                 [handler.claimedTouches removeObject: aTouch];

  70:             }

  71:         }

  72:     }

  73: }

  74:

  75: -(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event

  76: {

  77:     if( scrollTouch_ == touch ) {

  78:         scrollTouch_ = nil;

  79:     }

  80: }

  81:

  82: -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event

  83: {

  84:     if( scrollTouch_ == nil ) {

  85:         scrollTouch_ = touch;

  86:     } else {

  87:         return NO;

  88:     }

  89:

  90:     CGPoint touchPoint = [touch locationInView:[touch view]];

  91:     touchPoint = [[CCDirector sharedDirector] convertToGL:touchPoint];

  92:

  93:     startSwipe_ = touchPoint.y;

  94:     startSwipeLayerPos_ = [self position].y;

  95:     state_ = kFGScrollLayerStateIdle;

  96:     return YES;

  97: }

  98:

  99: - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event

 100: {

 101:     if( scrollTouch_ != touch ) {

 102:         return;

 103:     }

 104:

 105:     CGPoint touchPoint = [touch locationInView:[touch view]];

 106:     touchPoint = [[CCDirector sharedDirector] convertToGL:touchPoint];

 107:

 108:

 109:     // If finger is dragged for more distance then minimum - start sliding and cancel pressed buttons.

 110:     // Of course only if we not already in sliding mode

 111:     if ( (state_ != kFGScrollLayerStateSliding)

 112:         && (fabsf(touchPoint.y-startSwipe_) >= self.minimumTouchLengthToSlide) )

 113:     {

 114:         state_ = kFGScrollLayerStateSliding;

 115:

 116:         // Avoid jerk after state change.

 117:         startSwipe_ = touchPoint.y;

 118:         startSwipeLayerPos_ = [self position].y;

 119:         previousTouchPointY = touchPoint.y;

 120:

 121:         if (self.stealTouches)

 122:         {

 123:             [self claimTouch: touch];

 124:         }

 125:

 126:         if ([self.delegate respondsToSelector:@selector(scrollLayerScrollingStarted:)])

 127:         {

 128:             [self.delegate scrollLayerScrollingStarted: self];

 129:         }

 130:     }

 131:

 132:     if (state_ == kFGScrollLayerStateSliding)

 133:     {

 134:         CGFloat desiredY = startSwipeLayerPos_ + touchPoint.y - startSwipe_;

 135:         [self setPosition:ccp(0, desiredY)];

 136:     }

 137: }

 138: #endif

Basically, I borrowed these touch events handlers from CCScrollLayer, and I modified it a little bit for our own use. The structure is derived from CCScrollLayer, including the stealing touch events idea. Here we use variables startWipe_ and minimumTouchLengthToSlide_ to help us check whether user are sliding their fingers or simply touching the screen. If it is a sliding, we steal it; otherwise we send it to behind layers, e.g. items.

Step 4: Decides which items should be visible

With handling touch events, our scroll view is able to move accordingly. However, we need to restrict scroll view to some specific area, and that is the reason why we pass realBound as an initializing parameter. So, we need to update visibility of each item when moving scroll layer.

Put these two methods in the implementation file(.m file).

   1: /**

   2:  * According to current position, decide which pages are visible

   3:  */

   4: -(void)updatePagesAvailability{

   5:     CGPoint currentPos = [self position];

   6:     if (currentPos.y > 0) {

   7:         int visibleBoundUp = currentPos.y / pageHeight_;

   8:         visibleBoundUp = MIN([layers_ count], visibleBoundUp);

   9:         for (int i = 0; i < visibleBoundUp; i++) {

  10:             [[layers_ objectAtIndex:i] setVisible:NO];

  11:         }

  12:         if (visibleBoundUp < [layers_ count]) {

  13:             int visibleBoundDown = (currentPos.y + realBound.size.height) / pageHeight_;

  14:             visibleBoundDown = MIN([layers_ count] - 1, visibleBoundDown);

  15:             for (int i = visibleBoundUp; i <= visibleBoundDown; i++) {

  16:                 [[layers_ objectAtIndex:i] setVisible:YES];

  17:             }

  18:             if (visibleBoundDown < [layers_ count] - 1) {

  19:                 for (int i = visibleBoundDown + 1; i <= [layers_ count] - 1; i++) {

  20:                     [[layers_ objectAtIndex:i] setVisible:NO];

  21:                 }

  22:             }

  23:         }

  24:     }

  25:     else if (currentPos.y <= 0){

  26:         CGFloat gapY = -currentPos.y;

  27:         int visibleBound = (realBound.size.height - gapY) / pageHeight_;

  28:         // index visibleBound itself should be invisible

  29:         if (visibleBound < 0) {

  30:             for (int i = 0; i < [layers_ count]; i++) {

  31:                 [[layers_ objectAtIndex:i] setVisible:NO];

  32:             }

  33:             return;

  34:         }

  35:         visibleBound = MIN([layers_ count] - 1, visibleBound);

  36:         for (int i = 0; i <= visibleBound; i++) {

  37:             [[layers_ objectAtIndex:i] setVisible:YES];

  38:         }

  39:         for (int i = visibleBound + 1; i < [layers_ count]; i++) {

  40:             [[layers_ objectAtIndex:i] setVisible:NO];

  41:         }

  42:     }

  43: }

  44:

  45: -(void)setPosition:(CGPoint)position{

  46:     [super setPosition:position];

  47:     [self updatePagesAvailability];

  48: }

The first method here is to calculate each item’s visibility, and the second method here is to override setPosition to call update method. Besides, add one line to the updatePages method.

   1: [self updatePagesAvailability];

Step 5: Apply a simple sliding algorithm.

Okay, until now, we have finished the basic work of implementing a scroll view. Yet it is not a good one, since users’ sliding feelings are not fluent enough. Here, I have a very simple sliding algorithm. I know this is not a perfect solution, and this algorithm is far from Apple’s elegant sliding implementation. I just present it for lazy persons who just want it work. My simple idea is to calculate and store the finger moving speed. When users release their fingers, calculate the momentum according to their before finger moving speed and apply a following inertia effect. Below is how exactly I did it.

   1: // these two variables are to make a sliding effect on scroll view

   2: static CGFloat previousTouchPointY = -1;

   3: static CGFloat moveSpeed = 0;

   4: - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event

   5: {

   6:     if( scrollTouch_ != touch ) {

   7:         return;

   8:     }

   9:

  10:     CGPoint touchPoint = [touch locationInView:[touch view]];

  11:     touchPoint = [[CCDirector sharedDirector] convertToGL:touchPoint];

  12:

  13:

  14:     // If finger is dragged for more distance then minimum - start sliding and cancel pressed buttons.

  15:     // Of course only if we not already in sliding mode

  16:     if ( (state_ != kFGScrollLayerStateSliding)

  17:         && (fabsf(touchPoint.y-startSwipe_) >= self.minimumTouchLengthToSlide) )

  18:     {

  19:         state_ = kFGScrollLayerStateSliding;

  20:

  21:         // Avoid jerk after state change.

  22:         startSwipe_ = touchPoint.y;

  23:         startSwipeLayerPos_ = [self position].y;

  24:         previousTouchPointY = touchPoint.y;

  25:

  26:         if (self.stealTouches)

  27:         {

  28:             [self claimTouch: touch];

  29:         }

  30:

  31:         if ([self.delegate respondsToSelector:@selector(scrollLayerScrollingStarted:)])

  32:         {

  33:             [self.delegate scrollLayerScrollingStarted: self];

  34:         }

  35:     }

  36:

  37:     if (state_ == kFGScrollLayerStateSliding)

  38:     {

  39:         CGFloat desiredY = startSwipeLayerPos_ + touchPoint.y - startSwipe_;

  40:         [self setPosition:ccp(0, desiredY)];

  41:

  42:         // enable scroll bar to be visible

  43:         [scrollBar setVisible:YES];

  44:         [scrollBlock setVisible:YES];

  45:

  46:         // update scrolling effect variables

  47:         moveSpeed = touchPoint.y - previousTouchPointY;

  48:         previousTouchPointY = touchPoint.y;

  49:     }

  50: }

  51:

  52: /**

  53:  * After touching, generate an inertia effect.

  54:  */

  55: - (void)moveToDesiredPos:(CGFloat)desiredY{

  56:     CCAction* slidingAction = nil;

  57:     if (desiredY > maxVerticalPos_) {

  58:         slidingAction = [CCSequence actions:[CCMoveTo actionWithDuration:0.10 position:ccp([self position].x, desiredY)], [CCMoveTo actionWithDuration:0.15 position:ccp([self position].x, maxVerticalPos_)], nil];

  59:     }

  60:     else if (desiredY < 0){

  61:         slidingAction = [CCSequence actions:[CCMoveTo actionWithDuration:0.10 position:ccp([self position].x, desiredY)],[CCMoveTo actionWithDuration:0.15 position:ccp([self position].x, 0)], nil];

  62:     }

  63:     else{

  64:         CGFloat interPosY = (desiredY - [self position].y) * 0.7 + [self position].y;

  65:         slidingAction = [CCSequence actions:[CCMoveTo actionWithDuration:0.15 position:ccp([self position].x, interPosY)],[CCMoveTo actionWithDuration:0.3 position:ccp([self position].x, desiredY)], nil];

  66:     }

  67:     [self runAction:slidingAction];

  68: }

  69:

  70: - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event

  71: {

  72:     [scrollBar setVisible:NO];

  73:     [scrollBlock setVisible:NO];

  74:

  75:     if( scrollTouch_ != touch )

  76:         return;

  77:     scrollTouch_ = nil;

  78:

  79:     if (ABS(moveSpeed) > 10) {

  80:         CGFloat desiredDesY = [self position].y + moveSpeed * 5;

  81:         [self moveToDesiredPos:desiredDesY];

  82:     }

  83:     else{

  84:         if ([self position].y > maxVerticalPos_) {

  85:             [self runAction:[CCMoveTo actionWithDuration:0.3 position:ccp([self position].x, maxVerticalPos_)]];

  86:         }else if ([self position].y < 0){

  87:             [self runAction:[CCMoveTo actionWithDuration:0.3 position:ccp([self position].x, 0)]];

  88:         }

  89:     }

  90:

  91:     // restore scrolling effect variables to default value

  92:     moveSpeed = 0;

  93:     previousTouchPointY = -1;

  94: }

Step 6: What about the appearance of scroll view layer?

Everyone’s scroll view should look different, we need to add some decorative images to our viewer, e.g. we’d like to put our view into a frame, or we need a slider bar to indicate the current position of the whole list. What about those needs I just mentioned? Okay, here is the solution. You may create a class that inherit from this scroll layer, and specify whatever variables and images that you need to decorate your viewer. Here I provide my simple version. I wrote these variables into scroll layer class because they are very common for a standard scroll view, if you don’t need them, you may delete them or ignore them in your derived class.

Put below code in the definition file(.h file).

   1: /*Decoration and slide bars*/

   2: // Scroll bars on the right

   3: CCSprite* scrollBar;

   4: CGFloat scrollBarPosY;

   5:

   6: // Scroll block that indicates the current position in whole scorll view content

   7: CCSprite* scrollBlock;

   8: CGFloat scrollBlockUpperBound;

   9: CGFloat scrollBlockLowerBound;

  10:

  11: // Decoration

  12: // Holds position to maintain their position fixed even in setPosition

  13: CCSprite* upperBound;

  14: CGFloat upperBoundPosY;

  15: CCSprite* lowerBound;

  16: CGFloat lowerBoundPosY;

And add those code in setPosition method in .m file.

   1: CGFloat scrollBlockDesiredY = scrollBlockUpperBound - (scrollBlockUpperBound - scrollBlockLowerBound) * position.y / maxVerticalPos_;

   2: if (scrollBlockDesiredY > scrollBlockUpperBound) {

   3:     scrollBlockDesiredY = scrollBlockUpperBound;

   4: }else if (scrollBlockDesiredY < scrollBlockLowerBound){

   5:     scrollBlockDesiredY = scrollBlockLowerBound;

   6: }

   7: [scrollBlock setPosition:ccp([scrollBlock position].x, scrollBlockDesiredY - position.y)];

   8: [lowerBound setPosition:ccp([lowerBound position].x, lowerBoundPosY - position.y)];

   9: [upperBound setPosition:ccp([upperBound position].x, upperBoundPosY - position.y)];

  10: [scrollBar setPosition:ccp([scrollBar position].x, scrollBarPosY - position.y)];

Add below code in ccTouchEnded and ccTouchCanceled methods.

   1: [scrollBar setVisible:NO];

   2: [scrollBlock setVisible:NO];

Add below code in ccTouchMoved method.

   1: // enable scroll bar to be visible

   2: [scrollBar setVisible:YES];

   3: [scrollBlock setVisible:YES];

Now the only left thing is to provide proper images and values to the corresponding variables in your initialization method.

Finished Version

After reading above messy code fragments, you may want to download a complete version. Click here! 🙂

Conclusion

Scroll view is not a simple gadget that every game engine will provide. Besides, every game needs its own style scroll view. Therefore it is hard to offer an universally suitable scroll view. This blog offers a provides an adapter class for implementing your own scroll view. Implementing a scroll view by cocos2d is not a easy task, at least it is a tedious task. And it requires a lot of effort and carefulness in adjusting the relative position and calculating the visibility of each item. You may derive your own class from this layer, and this layer already help you achieve a lot of tedious work, e.g. touch events handling and scrolling. What left to do is to provide decorative images to make it look nice and elegant.

Advertisements
 
10 Comments

Posted by on October 5, 2012 in Technical notes

 

Tags: , , , , ,

10 responses to “Step by Step: How to build a scroll view by cocos2d

  1. Mr_Curious

    February 27, 2013 at 12:48 am

    How do you implement your scroll layer in cocos2d, can you give an example?

     
    • Glenn Dai

      February 27, 2013 at 9:19 am

      You can access the complete code through this link. https://github.com/sdnofootbird/Cocos2d-ScrollView

       
      • Mr_Curious

        February 27, 2013 at 11:26 pm

        Thanks for your quick reply. I downloaded the class and have imported it into my project, but I was actually asking how do I initiate it or get it working on one of my scenes?
        Is it something similar to this:
        FGScrolLayer *scrolLayer = [[FGScrollLayerLayer alloc] init]; ???

         
      • Glenn Dai

        February 28, 2013 at 12:42 am

        I’m sorry that i didn’t understand your question correctly. Actually, this is an adapter class rather than a self-contained class. You may find comments in file FGScrollLayer.h useful. You need to set some value before using it. If you still have trouble of using it, please write an email to me with your code, and I will try to help if I can.

         
  2. Shiju

    April 5, 2013 at 6:36 pm

    How to use this classes on my project

     
    • Glenn Dai

      April 6, 2013 at 12:49 am

      If you download the source code, check out the header files. I made some explanation there. Sorry that you can’t initialise one and use it. This class is actually an adapter class, you may need to add some parts, like your own sprites.

       
  3. Eric

    June 6, 2013 at 3:38 am

    Hello,

    When initialized FGScrollLayer, the variable “visibleRect” not working properly, using CGRect (0,0,480,320) the menu is not centered.

     
  4. uc

    October 15, 2013 at 11:21 am

    hi,哥们,我也正非常需要这个。可否给个具体使用你定义的scroll layer类的例子。另外它能否变成horizontal。

     

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: