├── AnimatedMenuScene.h ├── AnimatedMenuScene.m ├── DSMultilineLabelNode.h ├── DSMultilineLabelNode.m ├── MenuItemNode.h ├── MenuItemNode.m └── README.md /AnimatedMenuScene.h: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatedMenuScene.h 3 | // Party 4 | // 5 | // Created by Adnan Aftab on 8/25/15. 6 | // Copyright (c) 2015 CX. All rights reserved. 7 | // 8 | 9 | #import 10 | @class AnimatedMenuScene; 11 | 12 | @protocol AnimatedMenuSceneDelegate 13 | 14 | @optional 15 | - (void)animatedMenuScene:(AnimatedMenuScene*)animatedScene didSelectNodeAtIndex:(NSInteger)index; 16 | - (void)animatedMenuScene:(AnimatedMenuScene *)animatedScene didDeSelectNodeAtIndex:(NSInteger)index; 17 | 18 | @end 19 | 20 | @interface AnimatedMenuScene : SKScene 21 | @property (nonatomic, assign) BOOL allowMultipleSelection; 22 | @property (nonatomic, strong) NSArray *menuNodes; 23 | @property (nonatomic, weak) idanimatedSceneDelegate; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /AnimatedMenuScene.m: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatedMenuScene.m 3 | // Party 4 | // 5 | // Created by Adnan Aftab on 8/25/15. 6 | // Copyright (c) 2015 CX. All rights reserved. 7 | // 8 | 9 | #import "AnimatedMenuScene.h" 10 | #import "MenuItemNode.h" 11 | 12 | 13 | static NSString *SelectAnimation = @"SelectAction"; 14 | static NSString *DeselectAnimation = @"DeselectAnimation"; 15 | 16 | @interface AnimatedMenuScene() 17 | @property (nonatomic, strong) SKFieldNode *magneticField; 18 | @property (nonatomic, assign) CGPoint startPoint; 19 | @property (nonatomic, assign) NSTimeInterval touchStartTime; 20 | @property (nonatomic, assign) BOOL moving; 21 | @property (nonatomic, strong) SKNode *selectedNode; 22 | @property (nonatomic, strong) NSMutableArray *selectedNodes; 23 | @end 24 | @implementation AnimatedMenuScene 25 | - (instancetype)initWithSize:(CGSize)size 26 | { 27 | self = [super initWithSize:size]; 28 | if (self) 29 | { 30 | 31 | } 32 | return self; 33 | } 34 | - (void)didMoveToView:(SKView *)view 35 | { 36 | [super didMoveToView:view]; 37 | _selectedNodes = [NSMutableArray new]; 38 | [self configure]; 39 | } 40 | - (void)configure 41 | { 42 | self.magneticField = [SKFieldNode radialGravityField]; 43 | self.scaleMode = SKSceneScaleModeAspectFill; 44 | CGRect frame = self.frame; 45 | frame.size.width = self.magneticField.minimumRadius; 46 | frame.origin.x -= frame.size.width/2; 47 | frame.size.height = frame.size.height; 48 | frame.origin.y = frame.size.height - frame.size.height; 49 | self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:frame]; 50 | self.magneticField.position = CGPointMake(frame.size.width/2, frame.size.height / 2); 51 | } 52 | - (void)addChild:(SKNode *)node 53 | { 54 | 55 | CGFloat x = arc4random_uniform(self.frame.size.width - node.frame.size.width); 56 | CGFloat y = arc4random_uniform(self.frame.size.height - node.frame.size.height); 57 | 58 | node.position = CGPointMake(x, y); 59 | 60 | if (node.physicsBody == nil) 61 | { 62 | node.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:((SKShapeNode*)node).path]; 63 | } 64 | 65 | node.physicsBody.dynamic = YES; 66 | node.physicsBody.affectedByGravity = NO; 67 | node.physicsBody.allowsRotation = YES; 68 | node.physicsBody.mass = 0.3; 69 | node.physicsBody.friction = 0; 70 | node.physicsBody.linearDamping = 3; 71 | SKRange *xRange = [SKRange rangeWithLowerLimit:0 upperLimit:self.frame.size.width-node.frame.size.width]; 72 | SKRange *yRange = [SKRange rangeWithLowerLimit:0 upperLimit:self.frame.size.height-node.frame.size.height]; 73 | SKConstraint *constraint = [SKConstraint positionX:xRange Y:yRange]; 74 | node.constraints = @[constraint]; 75 | [super addChild:node]; 76 | } 77 | - (void)setMenuNodes:(NSArray *)menuNodes 78 | { 79 | if (_menuNodes) 80 | { 81 | [self.children makeObjectsPerformSelector:@selector(removeFromParent)]; 82 | } 83 | _selectedNode = nil; 84 | [_selectedNodes removeAllObjects]; 85 | _menuNodes = menuNodes; 86 | [self updateScene]; 87 | } 88 | - (void)updateScene 89 | { 90 | for (NSString *nodeTitle in _menuNodes) 91 | { 92 | MenuItemNode *menuItem = [MenuItemNode menuNodeWithTitle:nodeTitle]; 93 | 94 | [self addChild:menuItem]; 95 | } 96 | } 97 | - (SKNode *)nodeAtPoint:(CGPoint)p 98 | { 99 | SKNode *node = [super nodeAtPoint:p]; 100 | if (![node.parent isKindOfClass:[SKScene class]] && 101 | ![node isKindOfClass:[MenuItemNode class]] && 102 | node.parent != nil && 103 | !node.userInteractionEnabled) 104 | { 105 | node = node.parent; 106 | } 107 | return node; 108 | } 109 | - (void)deselectNode:(SKNode*)node 110 | { 111 | if (!node) 112 | { 113 | return; 114 | } 115 | [node removeActionForKey:SelectAnimation]; 116 | SKAction *action = [SKAction scaleTo:1 duration:0.2]; 117 | [node runAction:action completion:^{ 118 | [node removeAllActions]; 119 | }]; 120 | NSInteger index = [self.children indexOfObject:node]; 121 | if(index != NSNotFound) 122 | { 123 | [self.animatedSceneDelegate animatedMenuScene:self didDeSelectNodeAtIndex:index]; 124 | } 125 | } 126 | - (void)selectNode:(SKNode*)node 127 | { 128 | if (!_allowMultipleSelection) 129 | { 130 | [self deselectNode:_selectedNode]; 131 | if (_selectedNode == node) 132 | { 133 | _selectedNode = nil; 134 | return; 135 | } 136 | _selectedNodes = nil; 137 | } 138 | else 139 | { 140 | if ([_selectedNodes containsObject:node]) 141 | { 142 | [self deselectNode:node]; 143 | [_selectedNodes removeObject:node]; 144 | return; 145 | } 146 | } 147 | SKAction *action = [SKAction scaleTo:1.3 duration:0.2]; 148 | [node runAction:action withKey:SelectAnimation]; 149 | if (_allowMultipleSelection) 150 | { 151 | [self.selectedNodes addObject:node]; 152 | } 153 | else 154 | { 155 | _selectedNode = node; 156 | } 157 | NSInteger index = [self.children indexOfObject:node]; 158 | if (index != NSNotFound) 159 | { 160 | [self.animatedSceneDelegate animatedMenuScene:self didSelectNodeAtIndex:index]; 161 | } 162 | } 163 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 164 | { 165 | UITouch *touch = [touches anyObject]; 166 | self.startPoint = [touch locationInNode:self]; 167 | self.touchStartTime = touch.timestamp; 168 | } 169 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 170 | { 171 | _moving = YES; 172 | UITouch *touch = [touches anyObject]; 173 | CGPoint prePoint = [touch previousLocationInNode:self]; 174 | CGPoint point = [touch locationInNode:self]; 175 | 176 | float dx = point.x - prePoint.x; 177 | float dy = point.y - prePoint.y; 178 | 179 | for (SKNode *node in self.children) 180 | { 181 | CGVector vector = CGVectorMake(100 * dx, 100 * dy); 182 | [node.physicsBody applyForce:vector]; 183 | } 184 | 185 | } 186 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 187 | { 188 | if (!_moving) 189 | { 190 | UITouch *touch = [touches anyObject]; 191 | CGPoint location = [touch locationInNode:self]; 192 | SKNode *node = [self nodeAtPoint:location]; 193 | if (node) 194 | { 195 | [self selectNode:node]; 196 | } 197 | } 198 | _moving = NO; 199 | } 200 | @end 201 | -------------------------------------------------------------------------------- /DSMultilineLabelNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // DSMultilineLabelNode.h 3 | // DSMultilineLabelNode 4 | // 5 | // Created by Chris Allwein on 2/12/14. 6 | // Copyright (c) 2014 Downright Simple. All rights reserved. 7 | // 8 | // This software is licensed under an MIT-style license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | // 16 | 17 | #if TARGET_OS_IPHONE 18 | #define DSMultiLineLabelImage UIImage 19 | #define DSMultiLineLabelFont UIFont 20 | #else 21 | #define DSMultiLineLabelImage NSImage 22 | #define DSMultiLineLabelFont NSFont 23 | #endif 24 | 25 | 26 | #import 27 | 28 | @interface DSMultilineLabelNode : SKSpriteNode 29 | 30 | @property(retain, nonatomic) SKColor *fontColor; 31 | @property(copy, nonatomic) NSString *fontName; 32 | @property(nonatomic) CGFloat fontSize; 33 | @property(nonatomic) SKLabelHorizontalAlignmentMode horizontalAlignmentMode; 34 | @property(copy, nonatomic) NSString *text; 35 | @property(nonatomic) SKLabelVerticalAlignmentMode verticalAlignmentMode; 36 | @property(nonatomic, assign) CGFloat paragraphWidth; 37 | 38 | + (instancetype)labelNodeWithFontNamed:(NSString *)fontName; 39 | - (instancetype)initWithFontNamed:(NSString *)fontName; 40 | 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /DSMultilineLabelNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSMultilineLabelNode.m 3 | // DSMultilineLabelNode 4 | // 5 | // Created by Chris Allwein on 2/12/14. 6 | // Copyright (c) 2014 Downright Simple. All rights reserved. 7 | // 8 | // This software is licensed under an MIT-style license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | // 16 | 17 | #import "DSMultilineLabelNode.h" 18 | 19 | @implementation DSMultilineLabelNode 20 | 21 | #pragma mark init and convenience methods 22 | - (instancetype) init 23 | { 24 | self = [super init]; 25 | 26 | if (self) { 27 | 28 | //Initialize the same values as a default SKLabelNode 29 | self.fontColor = [SKColor whiteColor]; 30 | self.fontName = @"Helvetica"; 31 | self.fontSize = 32.0; 32 | 33 | self.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter; 34 | self.verticalAlignmentMode = SKLabelVerticalAlignmentModeBaseline; 35 | 36 | //Paint our initial texture 37 | [self retexture]; 38 | } 39 | 40 | return self; 41 | 42 | } 43 | 44 | //init method to support drop-in replacement for SKLabelNode 45 | - (instancetype)initWithFontNamed:(NSString *)fontName 46 | { 47 | self = [self init]; 48 | 49 | if (self) { 50 | self.fontName = fontName; 51 | } 52 | 53 | return self; 54 | } 55 | 56 | //Convenience method to support drop-in replacement for SKLabelNode 57 | + (instancetype)labelNodeWithFontNamed:(NSString *)fontName 58 | { 59 | DSMultilineLabelNode *node = [[DSMultilineLabelNode alloc] initWithFontNamed:fontName]; 60 | 61 | return node; 62 | } 63 | 64 | #pragma mark setters for SKLabelNode properties 65 | //For each of the setters, after we set the appropriate property, we call the 66 | //retexture method to generate and apply our new texture to the node 67 | 68 | -(void) setFontColor:(SKColor *)fontColor 69 | { 70 | _fontColor = fontColor; 71 | [self retexture]; 72 | } 73 | 74 | -(void) setFontName:(NSString *)fontName 75 | { 76 | _fontName = fontName; 77 | [self retexture]; 78 | } 79 | 80 | -(void) setFontSize:(CGFloat)fontSize 81 | { 82 | _fontSize = fontSize; 83 | [self retexture]; 84 | } 85 | 86 | -(void) setHorizontalAlignmentMode:(SKLabelHorizontalAlignmentMode)horizontalAlignmentMode 87 | { 88 | _horizontalAlignmentMode = horizontalAlignmentMode; 89 | [self retexture]; 90 | } 91 | 92 | -(void) setText:(NSString *)text 93 | { 94 | _text = text; 95 | [self retexture]; 96 | } 97 | 98 | -(void) setVerticalAlignmentMode:(SKLabelVerticalAlignmentMode)verticalAlignmentMode 99 | { 100 | _verticalAlignmentMode = verticalAlignmentMode; 101 | [self retexture]; 102 | } 103 | 104 | -(void)setParagraphWidth:(CGFloat)paragraphWidth { 105 | 106 | _paragraphWidth = paragraphWidth; 107 | [self retexture]; 108 | 109 | } 110 | 111 | //Generates and applies new textures based on the current property values 112 | -(void) retexture 113 | { 114 | DSMultiLineLabelImage *newTextImage = [self imageFromText:self.text]; 115 | SKTexture *newTexture =[SKTexture textureWithImage:newTextImage]; 116 | 117 | SKSpriteNode *selfNode = (SKSpriteNode*) self; 118 | selfNode.texture = newTexture; 119 | 120 | //Resetting the texture also reset the anchorPoint. Let's recenter it. 121 | selfNode.anchorPoint = CGPointMake(0.5, 0.5); 122 | 123 | } 124 | 125 | -(DSMultiLineLabelImage *)imageFromText:(NSString *)text 126 | { 127 | //First we define a paragrahp style, which has the support for doing the line breaks and text alignment that we require 128 | NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 129 | paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; //To get multi-line 130 | paragraphStyle.alignment = [self mapSkLabelHorizontalAlignmentToNSTextAlignment:self.horizontalAlignmentMode]; 131 | paragraphStyle.lineSpacing = 1; 132 | 133 | //Create the font using the values set by the user 134 | DSMultiLineLabelFont *font = [DSMultiLineLabelFont fontWithName:self.fontName size:self.fontSize]; 135 | 136 | if (!font) { 137 | font = [DSMultiLineLabelFont fontWithName:@"Helvetica" size:self.fontSize]; 138 | NSLog(@"The font you specified was unavailable. Defaulted to Helvetica."); 139 | // NSLog(@"The font you specified was unavailable. Defaulted to Helvetica. Here is a list of available fonts: %@", [DSMultiLineLabelFont familyNames]); //only available for debugging on iOS 140 | // NSLog(@"Here is a list of variations to %@: %@", _fontName, [DSMultiLineLabelFont familyNames]); 141 | } 142 | 143 | //Create our textAttributes dictionary that we'll use when drawing to the graphics context 144 | NSMutableDictionary *textAttributes = [NSMutableDictionary dictionary]; 145 | 146 | //Font Name and size 147 | [textAttributes setObject:font forKey:NSFontAttributeName]; 148 | 149 | //Line break mode and alignment 150 | [textAttributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName]; 151 | 152 | //Font Color 153 | [textAttributes setObject:self.fontColor forKey:NSForegroundColorAttributeName]; 154 | 155 | 156 | //Calculate the size that the text will take up, given our options. We use the full screen size for the bounds 157 | if (_paragraphWidth == 0) { 158 | _paragraphWidth = self.scene.size.width; 159 | } 160 | #if TARGET_OS_IPHONE 161 | CGRect textRect = [text boundingRectWithSize:CGSizeMake(_paragraphWidth, self.scene.size.height) 162 | options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine 163 | attributes:textAttributes 164 | context:nil]; 165 | 166 | #else 167 | CGRect textRect = [text boundingRectWithSize:CGSizeMake(_paragraphWidth, self.scene.size.height) 168 | options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine 169 | attributes:textAttributes]; 170 | #endif 171 | //iOS7 uses fractional size values. So we needed to ceil it to make sure we have enough room for display. 172 | textRect.size.height = ceil(textRect.size.height); 173 | textRect.size.width = ceil(textRect.size.width); 174 | 175 | //Mac build crashes when the size is nothing - this also skips out on unecessary cycles below when the size is nothing 176 | if (textRect.size.width == 0 || textRect.size.height == 0) { 177 | return Nil; 178 | } 179 | 180 | //The size of the bounding rect is going to be the size of our new node, so set the size here. 181 | SKSpriteNode *selfNode = (SKSpriteNode*) self; 182 | selfNode.size = textRect.size; 183 | 184 | #if TARGET_OS_IPHONE 185 | //Create the graphics context 186 | UIGraphicsBeginImageContextWithOptions(textRect.size,NO,0.0); 187 | 188 | //Actually draw the text into the context, using our defined attributed 189 | [text drawInRect:textRect withAttributes:textAttributes]; 190 | 191 | //Create the image from the context 192 | DSMultiLineLabelImage *image = UIGraphicsGetImageFromCurrentImageContext(); 193 | 194 | //Close the context 195 | UIGraphicsEndImageContext(); 196 | #else 197 | 198 | DSMultiLineLabelImage *image = [[DSMultiLineLabelImage alloc] initWithSize:textRect.size]; 199 | /* 200 | // this section may or may not be necessary (it builds and runs without, but I don't have enough experience to know if this makes things run smoother in any way, or if the stackexchange article was entirely purposed for something else) 201 | NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:textRect.size.width pixelsHigh:textRect.size.height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:0 bitsPerPixel:0]; 202 | 203 | [image addRepresentation:imageRep]; 204 | 205 | */ 206 | [image lockFocus]; 207 | 208 | [text drawInRect:textRect withAttributes:textAttributes]; 209 | 210 | [image unlockFocus]; 211 | 212 | 213 | #endif 214 | 215 | return image; 216 | } 217 | 218 | //Performs translation between the SKLabelHorizontalAlignmentMode supported by SKLabelNode and the NSTextAlignment required for string drawing 219 | 220 | #if TARGET_OS_IPHONE 221 | 222 | -(NSTextAlignment) mapSkLabelHorizontalAlignmentToNSTextAlignment:(SKLabelHorizontalAlignmentMode)alignment 223 | { 224 | switch (alignment) { 225 | case SKLabelHorizontalAlignmentModeLeft: 226 | return NSTextAlignmentLeft; 227 | break; 228 | 229 | case SKLabelHorizontalAlignmentModeCenter: 230 | return NSTextAlignmentCenter; 231 | break; 232 | 233 | case SKLabelHorizontalAlignmentModeRight: 234 | return NSTextAlignmentRight; 235 | break; 236 | 237 | default: 238 | break; 239 | } 240 | 241 | return NSTextAlignmentLeft; 242 | } 243 | 244 | #else 245 | 246 | -(NSTextAlignment) mapSkLabelHorizontalAlignmentToNSTextAlignment:(SKLabelHorizontalAlignmentMode)alignment 247 | { 248 | switch (alignment) { 249 | case SKLabelHorizontalAlignmentModeLeft: 250 | return kCTTextAlignmentLeft; 251 | break; 252 | 253 | case SKLabelHorizontalAlignmentModeCenter: 254 | return kCTTextAlignmentCenter; 255 | break; 256 | 257 | case SKLabelHorizontalAlignmentModeRight: 258 | return kCTTextAlignmentRight; 259 | break; 260 | 261 | default: 262 | break; 263 | } 264 | 265 | return kCTTextAlignmentLeft; 266 | } 267 | 268 | #endif 269 | 270 | @end 271 | -------------------------------------------------------------------------------- /MenuItemNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // MenuItemNode.h 3 | // Party 4 | // 5 | // Created by Adnan Aftab on 8/25/15. 6 | // Copyright (c) 2015 CX. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MenuItemNode : SKShapeNode 12 | 13 | @property (nonatomic, strong) NSString *title; 14 | 15 | + (instancetype)menuNode; 16 | + (instancetype)menuNodeWithTitle:(NSString*)title; 17 | @end 18 | -------------------------------------------------------------------------------- /MenuItemNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // MenuItemNode.m 3 | // Party 4 | // 5 | // Created by Adnan Aftab on 8/25/15. 6 | // Copyright (c) 2015 CX. All rights reserved. 7 | // 8 | 9 | #import "MenuItemNode.h" 10 | #import "DSMultilineLabelNode.h" 11 | 12 | @interface MenuItemNode () 13 | @property (nonatomic, strong) DSMultilineLabelNode *titleNode; 14 | @end 15 | 16 | @implementation MenuItemNode 17 | 18 | + (instancetype)menuNode 19 | { 20 | MenuItemNode *menuNode = [MenuItemNode new]; 21 | [menuNode setPath:CGPathCreateWithRoundedRect(CGRectMake(0, 0, 100, 100), 50, 50, nil)]; 22 | menuNode.strokeColor = menuNode.fillColor = [UIColor redColor]; 23 | return menuNode; 24 | } 25 | + (instancetype)menuNodeWithTitle:(NSString *)title 26 | { 27 | MenuItemNode *menuNode = [self menuNode]; 28 | menuNode.title = title; 29 | return menuNode; 30 | } 31 | - (void)setTitle:(NSString *)title 32 | { 33 | _title = title; 34 | if (!_titleNode) 35 | { 36 | _titleNode = [[DSMultilineLabelNode alloc] initWithFontNamed:@"HelveticaNeue-Bold"]; 37 | _titleNode.fontSize = 12; 38 | _titleNode.paragraphWidth = 80; 39 | _titleNode.name = @"title"; 40 | _titleNode.fontColor = [UIColor whiteColor]; 41 | _titleNode.position = CGPointZero; 42 | _titleNode.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter; 43 | _titleNode.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter; 44 | _titleNode.userInteractionEnabled = NO; 45 | [self addChild:_titleNode]; 46 | } 47 | _titleNode.text = title; 48 | } 49 | - (void)addChild:(SKNode *)node 50 | { 51 | node.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); 52 | [super addChild:node]; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AnimatedMenuPool 2 | Animated Menu Pool (Similar like apple music genre section screen) 3 | is a component which you can use to create a pool of subviews which can animated and will use physicis to animate on siwpe. 4 | Its very easy to use you can add SKShpaeNode as menu item. 5 | 6 | **Usage** 7 | 8 | 1. Create a SKView object and add it to your view, then create AnimatedMenuScene and present in SKView. 9 | 10 | 2. To add menu item set menuNodes array property (should be an array of NSStrings) 11 | 12 | 3. If need multiple selections set allowMultipleSelection = YES (Default is NO) 13 | 14 | 4. Set animatedSceneDelegate if you want to get notify when user selects menuItem (node) 15 | 16 | 17 | ```objectivec 18 | _skView = [[SKView alloc] initWithFrame:self.view.bounds]; 19 | [self.view insertSubview:_skView atIndex:0]; 20 | _animatedMenuScene = [[AnimatedMenuScene alloc] initWithSize:self.skView.bounds.size]; 21 | _animatedMenuScene.animatedSceneDelegate = self;// If you want to get notify when an item get selected 22 | _animatedMenuScene.menuNodes = _typeArray; 23 | _animatedMenuScene.backgroundColor = [UIColor blueColor]; 24 | [_skView presentScene:_animatedMenuScene]; 25 | ``` 26 | 27 | **Credit** 28 | 29 | This component use DSMultilineLabelNode to use wrap text in two lines you can find that here https://github.com/downrightsimple/DSMultilineLabelNode 30 | 31 | 32 | **Example** 33 | 34 | [Video](https://youtu.be/XfvnCTyh8sQ) 35 | 36 | [![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/XfvnCTyh8sQ/1.jpg)](http://www.youtube.com/watch?v=XfvnCTyh8sQ) 37 | --------------------------------------------------------------------------------