Este pequeño snippet os permitirá crear un menu con N elementos separados en M filas. Para el ejemplo que os he puesto he creado una lista de 9 botones agrupados en 2 filas.
Pero como una imagen vale mas que 1000 palabras, aquí os paso un video que os mostrará el funcionamiento del mismo.
[yframe url='http://www.youtube.com/watch?v=FcK1uQXfLGs&feature=channel_video_title']
Por último, os adjunto el código fuente del selector de menu, solo necesitareis importar las clasesJACSelector.h y JACSelector.m a vuestro proyecto.
Para cualquier duda, dejar un comentario.
//
// JACSelector.h
// SelectorMenu
//
// Created by Jose Antonio Andújar Clavell on 01/02/11.
// Alias "jandujar"
//
// More snippets on http://www.jandujar.com
//
// License http://creativecommons.org/licenses/by/3.0/
#import "cocos2d.h"
@interface JACSelector : CCLayer
{
tCCMenuState state; // State of our menu grid. (Eg. waiting, tracking touch, cancelled, etc)
CCMenuItem *selectedItem; // Menu item that was selected/active.
CGPoint padding; // Padding in between menu items.
CGPoint menuOrigin; // Origin position of the entire menu grid.
CGPoint touchOrigin; // Where the touch action began.
CGPoint touchStop; // Where the touch action stopped.
CGPoint relativePosition; // Position of the menu when touch action began
float fMaxY; // Max offset of menu position
bool bMoving; // Is the menu currently moving?
float fMoveDelta; // Distance from origin of touch and current frame.
float fAnimSpeed; // 0.0-1.0 value determining how slow/fast to animate the paging.
}
+(id) menuWithArray:(NSMutableArray*)items rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad ;
-(id) initWithArray:(NSMutableArray*)items rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad ;
-(void) buildMenuSelector:(int)rows itemWidth:(int)iw itemHeight:(int)ih;
-(CCMenuItem*) GetItemWithinTouch:(UITouch*)touch;
- (CGPoint) GetRelativePosition:(float)offset;
- (void) checkLimits;
@property (nonatomic, readwrite) CGPoint padding;
@property (nonatomic, readwrite) CGPoint menuOrigin;
@property (nonatomic, readwrite) CGPoint touchOrigin;
@property (nonatomic, readwrite) CGPoint touchStop;
@property (nonatomic, readwrite) CGPoint relativePosition;
@property (nonatomic, readwrite) bool bMoving;
@property (nonatomic, readwrite) float fMoveDelta;
@property (nonatomic, readwrite) float fAnimSpeed;
@property (nonatomic, readwrite) float fMaxY;
@end
//
// JACSelector.m
// SelectorMenu
//
// Created by Jose Antonio Andújar Clavell on 01/02/11.
// Alias "jandujar"
//
// More snippets on http://www.jandujar.com
//
// License http://creativecommons.org/licenses/by/3.0/
#import "JACSelector.h"
@implementation JACSelector
@synthesize padding;
@synthesize menuOrigin;
@synthesize touchOrigin;
@synthesize touchStop;
@synthesize relativePosition;
@synthesize bMoving;
@synthesize fMoveDelta;
@synthesize fAnimSpeed;
@synthesize fMaxY;
+(id) menuWithArray:(NSMutableArray*)items rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad
{
return [[self alloc] initWithArray:items rows:rows position:pos padding:pad];
}
-(id) initWithArray:(NSMutableArray*)items rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad
{
if ((self = [super init]))
{
self.isTouchEnabled = YES;
CCMenuItem* item =[items objectAtIndex:0];
int itemWidth = item.contentSizeInPixels.width;
int itemHeight = item.contentSizeInPixels.height;
CGSize size = CGSizeMake(itemWidth+2*pad.x,rows*(itemHeight +pad.y) +pad.y);
[self setContentSize:size];
int z = 1;
for (id item in items)
{
[self addChild:item z:z tag:z];
++z;
}
padding = pad;
bMoving = false;
menuOrigin = pos;
fAnimSpeed = 1;
[self buildMenuSelector:rows itemWidth:itemWidth itemHeight:itemHeight];
self.position = menuOrigin;
}
return self;
}
-(void) dealloc
{
[super dealloc];
}
-(void) buildMenuSelector:(int)rows itemWidth:(int)iw itemHeight:(int)ih
{
int row = 0;
int i=0;
fMaxY = menuOrigin.y;
for (CCMenuItem* item in self.children)
{
// Calculate the position of our menu item.
item.position = CGPointMake( padding.x + iw/2,
self.contentSize.height +ih/2 - (row+1)*((ih) + padding.y));
if(row%rows==(rows-1)){
fMaxY = -item.position.y + rows*(ih + padding.y) -ih/2 + menuOrigin.y ;
}
++row;
i++;
}
}
-(void) addChild:(CCMenuItem*)child z:(int)z tag:(int)aTag
{
return [super addChild:child z:z tag:aTag];
}
-(CCMenuItem*) GetItemWithinTouch:(UITouch*)touch
{
// Get the location of touch.
CGPoint touchLocation = [[CCDirector sharedDirector] convertToGL: [touch locationInView: [touch view]]];
// Parse our menu items and see if our touch exists within one.
for (CCMenuItem* item in [self children])
{
CGPoint local = [item convertToNodeSpace:touchLocation];
CGRect r = [item rect];
r.origin = CGPointZero;
// If the touch was within this item. Return the item.
if (CGRectContainsPoint(r, local))
{
return item;
}
}
// Didn't touch an item.
return nil;
}
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES];
}
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
// Convert and store the location the touch began at.
touchOrigin = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];
relativePosition = CGPointMake(self.position.x, self.position.y);
// If we weren't in "waiting" state bail out.
if (state != kCCMenuStateWaiting)
{
return NO;
}
// Activate the menu item if we are touching one.
selectedItem = [self GetItemWithinTouch:touch];
[selectedItem selected];
state = kCCMenuStateTrackingTouch;
return YES;
}
// Touch has ended. Process sliding of menu or press of menu item.
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
// User has been sliding the menu.
if( bMoving )
{
bMoving = false;
[self checkLimits];
[selectedItem unselected];
}
// User wasn't sliding menu and simply tapped the screen. Activate the menu item.
else
{
[selectedItem unselected];
[selectedItem activate];
}
// Back to waiting state.
state = kCCMenuStateWaiting;
}
// Check the limits of the menu Selector
- (void) checkLimits
{
if (self.position.y < (menuOrigin.y)) {
// Perform the action
id action = [CCMoveTo actionWithDuration:(fAnimSpeed*0.5) position:CGPointMake(self.position.x, menuOrigin.y)];
[self runAction:action];
}else if (self.position.y > (fMaxY)) {
// Perform the action
id action = [CCMoveTo actionWithDuration:(fAnimSpeed*0.5) position:CGPointMake(self.position.x, fMaxY)];
[self runAction:action];
}
}
-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
[selectedItem unselected];
state = kCCMenuStateWaiting;
}
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
// Calculate the current touch point during the move.
touchStop = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];
// Distance between the origin of the touch and current touch point.
fMoveDelta = touchStop.y - touchOrigin.y;
// Set our position.
[self setPosition:[self GetRelativePosition:fMoveDelta]];
bMoving = true;
}
- (CGPoint) GetRelativePosition:(float)offset
{
return CGPointMake(relativePosition.x,relativePosition.y+offset);
}
#pragma mark Clipping logic
- (void) visit {
if (!self.visible)
return;
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(menuOrigin.x, menuOrigin.y, self.contentSize.width , self.contentSize.height);
//glScissor(menuOrigin.x, menuOrigin.y, 100 , 100);
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
@end
Hola, interesante lo que estas planteando en este post, yo soy nuevo en el mundo de las aplicaciones para Iphone e Ipad y me gustaria conocer mucho más, actualmente estoy haciendo una aplicación que necesitaria lo que tú estas explicando en esta publicación. Cómo podría utilizar estas clases para implementar un menú así???
ResponderEliminar