Search code examples
ioscocos2d-iphone

CCScrollView scroll and touch events never firing


I can't find any helpful tutorials or explanation on how to use a CCScrollView. I have a grid-layout of sprites and labels (listing achievements for an iOS game). There are more than can fit on the screen so I want the user to be able to scroll.

To scroll, the user would swipe/pan upwards, to reveal the sprites etc which are lower.

I've found a few code samples and they seem to indicate you just need to add your content node to the scroll node and it will take care of the rest.

It doesn't seem to work. There's no scroll, and the pan/touch events on the scroll layer never seem to fire. The close button I have at the same child (sibling to the scroll view) no longer works as well.

I'm not using SpriteBuilder.

// Node to hold all sprites/labels
scrollContents = [CCNode node];

// I add a bunch of sprites/labels in a grid view
for( NSString *key in badgeKeys ){

    // logic to load the sprite would be here

    CCSprite *badge = [CCSprite spriteWithSpriteFrame:frame];
    badge.positionType = CCPositionTypeNormalized;
    badge.position = ccp(xPos,yPos);
    [scrollContents addChild:badge];

    // some logic to increment x/y position logic, for grid layout

}

// Scroll view
scrollView = [[CCScrollView alloc] initWithContentNode:scrollContents];
scrollView.horizontalScrollEnabled = NO;
scrollView.verticalScrollEnabled = YES;
[scrollView setBounces:NO];

// My sprites never even show unless I manually set this
scrollContents.contentSize = CGSizeMake(self.contentSize.width,960);
NSLog(@"scrollContents contentsize: %f %f", scrollContents.contentSize.width,scrollContents.contentSize.height);

[self addChild:scrollView];

Solution

  • ok, here is a working example (i deconstructed part of my code to give you a fully working code sample) of a scrolling menu with 'live' buttons inside. I just tested this 'deconstruction' , it works

    - (void) scrollingMenuWithCharmsTest {
    
    //    setup something to scroll
    
    GameInventory *gi = [GameInventory sharedGameInventory];
    while (gi.armorCharms.count < 20) {
        [gi addArmorCharm:[ArmorCharm createRandomArmorCharm]];
    }
    
    CCNode *contentNode = [self charmsContentNodeFor:gi.armorCharms
                                         showEquiped:NO
                             spacingBetweenMenuItems:8
                                              target:self
                                            selector:@selector(onArmorCharmSelected:)];
    
    // setup a clipping node to crop out the CCScrollingMenu
    
    
    CCNodeColor *ccn = [CCNodeColor nodeWithColor:[CCColor blackColor] width:180 height:200];
    ccn.anchorPoint = ccp(0, 0);
    CCClippingNode *cn = [CCClippingNode clippingNodeWithStencil:ccn];
    cn.alphaThreshold = 0.05f;
    [self addChild:cn];
    cn.inverted            = NO;
    cn.positionInPointsV   = ccp(50, 50);
    cn.anchorPoint         = ccp(0, 0);
    cn.contentSizeInPoints = CGSizeMake(180, 200);
    
    // setup scrolling menu
    
    CCScrollView * bsm = [[CCScrollView alloc] initWithContentNode:contentNode];
    bsm.contentSize=CGSizeMake(180,200);
    
    [cn addChild:bsm];
    bsm.position                = ccp(0, 0);
    bsm.bounces                 = YES;
    bsm.pagingEnabled           = NO;
    bsm.verticalScrollEnabled   = YES;
    bsm.horizontalScrollEnabled = NO;
    
    bsm.contentSizeInPoints = CGSizeMake(180, 200); // inPoints only after the node has a parent
    
    for (CharmAbstractBoxMenuItem *lmi in bsm.contentNode.children) {
        TRACE(@"item %@ is at %@", lmi.item.description, NSStringFromCGPoint(lmi.positionInPointsV));
    }
    TRACE(@"number of pages : %i", bsm.numVerticalPages);
    
    }
    
    - (CCNode *)charmsContentNodeFor:(NSDictionary *)keyedItems
                         showEquiped:(BOOL)isShowEquiped
             spacingBetweenMenuItems:(float)inSpacing
                              target:(id)inTarget
                            selector:(SEL)inSelector {
    
    NSSortDescriptor *sortOrder  = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES];
    NSArray          *sortedKeys = [[keyedItems allKeys] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortOrder]];
    
    float initialY = 0;
    float currentY = initialY;
    
    NSUInteger      itemNumber   = 0;
    CGFloat         width        = 0;
    CGFloat         height       = 0;
    CCNode          *contentNode = [CCNode node];
    for (NSUInteger loopi        = 0; loopi < [sortedKeys count]; loopi++) {
        NSString      *key = [sortedKeys objectAtIndex:loopi];
        CharmAbstract *ci  = [keyedItems objectForKey:key];
    
        if (ci) {
            CharmAbstractBoxMenuItem *cmi = [CharmAbstractBoxMenuItem itemBoxFor:ci
                                                                          target:inTarget
                                                                        selector:inSelector
            ];
    
            cmi.toolTip  = ci.toolTip;
            cmi.position = ccp(deviceOffset(0), currentY);
            cmi.key      = key;
            [contentNode addChild:cmi z:0 name:[NSString stringWithFormat:@"%li", (long) itemNumber]];
    
            currentY += cmi.contentSizeInPoints.height + inSpacing;
            itemNumber++;
            if (cmi.contentSize.width > width) width = cmi.contentSize.width;
            height += cmi.contentSize.height;
            if (loopi < sortedKeys.count - 1) height += inSpacing;
        }
        else {
            MPLOG(@"*** Key [%@] yielded no items.", key);
        }
    
    }
    contentNode.contentSizeType = CCSizeTypePoints;
    contentNode.contentSize     = CGSizeMake(width, height);
    return contentNode;
    
    }
    

    some notes :

    • i gave you my 'build content node' routine so you know the ins and outs of positions and sizes.
    • my charmBoxMenuItemss derive from 'CCButton' and are hot ... In the full version of this code snippet, i extended CCScrollView to prevent the buttons from being 'hot' outside the crop area (although they are cropped out from view, they are still 'visible' by default, and could respond when a random tap occurs above or below the crop area).
    • For clipping node with stencil, you need to add this in your setupCocos2dWithOptions line:

      CCSetupDepthFormat : [NSNumber numberWithUnsignedInt:GL_DEPTH24_STENCIL8_OES]

    as seen on a simulator near you :)