diff --git a/AwesomeMenu.podspec.json b/AwesomeMenu.podspec.json new file mode 100644 index 0000000..f9f9b4f --- /dev/null +++ b/AwesomeMenu.podspec.json @@ -0,0 +1,20 @@ +{ + "name": "AwesomeMenu", + "version": "1.0.0", + "summary": "Path 2.0 menu using CoreAnimation :).", + "homepage": "https://github.com/levey/AwesomeMenu", + "license": "MIT", + "authors": { + "levey": "levey.zhu@gmail.com" + }, + "source": { + "git": "https://github.com/levey/AwesomeMenu.git", + "tag": "1.0.0" + }, + "platforms": { + "ios": null + }, + "source_files": "AwesomeMenu/AwesomeMenu/*.{h,m}", + "resources": "AwesomeMenu/Images/*.png", + "requires_arc": false +} \ No newline at end of file diff --git a/AwesomeMenu/AwesomeMenu/AwesomeMenu.h b/AwesomeMenu/AwesomeMenu/AwesomeMenu.h index 87a077e..17b9a89 100644 --- a/AwesomeMenu/AwesomeMenu/AwesomeMenu.h +++ b/AwesomeMenu/AwesomeMenu/AwesomeMenu.h @@ -17,7 +17,7 @@ @property (nonatomic, strong) AwesomeMenuItem *startButton; @property (nonatomic, getter = isExpanded) BOOL expanded; -@property (nonatomic, weak) id delegate; +@property (nonatomic, assign) id delegate; @property (nonatomic, strong) UIImage *image; @property (nonatomic, strong) UIImage *highlightedImage; @@ -35,6 +35,7 @@ @property (nonatomic, assign) CGFloat closeRotation; @property (nonatomic, assign) CGFloat animationDuration; @property (nonatomic, assign) BOOL rotateAddButton; +@property (nonatomic, assign) CGFloat addRotation; - (id)initWithFrame:(CGRect)frame startItem:(AwesomeMenuItem*)startItem menuItems:(NSArray *)menuItems; diff --git a/AwesomeMenu/AwesomeMenu/AwesomeMenu.m b/AwesomeMenu/AwesomeMenu/AwesomeMenu.m index c2417e4..1558907 100644 --- a/AwesomeMenu/AwesomeMenu/AwesomeMenu.m +++ b/AwesomeMenu/AwesomeMenu/AwesomeMenu.m @@ -21,13 +21,14 @@ static CGFloat const kAwesomeMenuDefaultCloseRotation = M_PI * 2; static CGFloat const kAwesomeMenuDefaultAnimationDuration = 0.5f; static CGFloat const kAwesomeMenuStartMenuDefaultAnimationDuration = 0.3f; +static CGFloat const kAwesomeMenuDefaultAddRotation = -M_PI_4; static CGPoint RotateCGPointAroundCenter(CGPoint point, CGPoint center, float angle) { CGAffineTransform translation = CGAffineTransformMakeTranslation(center.x, center.y); CGAffineTransform rotation = CGAffineTransformMakeRotation(angle); CGAffineTransform transformGroup = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformInvert(translation), rotation), translation); - return CGPointApplyAffineTransform(point, transformGroup); + return CGPointApplyAffineTransform(point, transformGroup); } @interface AwesomeMenu () @@ -44,7 +45,7 @@ @implementation AwesomeMenu { BOOL _isAnimating; } -@synthesize nearRadius, endRadius, farRadius, timeOffset, rotateAngle, menuWholeAngle, startPoint, expandRotation, closeRotation, animationDuration, rotateAddButton; +@synthesize nearRadius, endRadius, farRadius, timeOffset, rotateAngle, menuWholeAngle, startPoint, expandRotation, closeRotation, animationDuration, rotateAddButton, addRotation; @synthesize expanded = _expanded; #pragma mark - Initialization & Cleaning up @@ -65,9 +66,10 @@ - (id)initWithFrame:(CGRect)frame startItem:(AwesomeMenuItem*)startItem menuItem self.closeRotation = kAwesomeMenuDefaultCloseRotation; self.animationDuration = kAwesomeMenuDefaultAnimationDuration; self.rotateAddButton = YES; - + self.addRotation = kAwesomeMenuDefaultAddRotation; + self.menuItems = menuItems; - + // assign startItem to "Add" Button. self.startButton = startItem; self.startButton.delegate = self; @@ -93,46 +95,46 @@ - (void)setStartPoint:(CGPoint)aPoint #pragma mark - Images - (void)setImage:(UIImage *)image { - self.startButton.image = image; + self.startButton.image = image; } - (UIImage*)image { - return self.startButton.image; + return self.startButton.image; } - (void)setHighlightedImage:(UIImage *)highlightedImage { - self.startButton.highlightedImage = highlightedImage; + self.startButton.highlightedImage = highlightedImage; } - (UIImage*)highlightedImage { - return self.startButton.highlightedImage; + return self.startButton.highlightedImage; } - (void)setContentImage:(UIImage *)contentImage { - self.startButton.contentImageView.image = contentImage; + self.startButton.contentImageView.image = contentImage; } - (UIImage*)contentImage { - return self.startButton.contentImageView.image; + return self.startButton.contentImageView.image; } - (void)setHighlightedContentImage:(UIImage *)highlightedContentImage { - self.startButton.contentImageView.highlightedImage = highlightedContentImage; + self.startButton.contentImageView.highlightedImage = highlightedContentImage; } - (UIImage*)highlightedContentImage { - return self.startButton.contentImageView.highlightedImage; + return self.startButton.contentImageView.highlightedImage; } - + #pragma mark - UIView's methods - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { // if the menu is animating, prevent touches - if (_isAnimating) + if (_isAnimating) { return NO; } @@ -157,7 +159,7 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event - (void)AwesomeMenuItemTouchesBegan:(AwesomeMenuItem *)item { - if (item == self.startButton) + if (item == self.startButton) { self.expanded = ![self isExpanded]; } @@ -165,7 +167,7 @@ - (void)AwesomeMenuItemTouchesBegan:(AwesomeMenuItem *)item - (void)AwesomeMenuItemTouchesEnd:(AwesomeMenuItem *)item { // exclude the "add" button - if (item == self.startButton) + if (item == self.startButton) { return; } @@ -173,7 +175,7 @@ - (void)AwesomeMenuItemTouchesEnd:(AwesomeMenuItem *)item CAAnimationGroup *blowup = [self _blowupAnimationAtPoint:item.center]; [item.layer addAnimation:blowup forKey:@"blowup"]; item.center = item.startPoint; - + // shrink other menu buttons for (int i = 0; i < [self.menuItems count]; i ++) { @@ -187,13 +189,17 @@ - (void)AwesomeMenuItemTouchesEnd:(AwesomeMenuItem *)item otherItem.center = otherItem.startPoint; } _expanded = NO; - + // rotate start button - float angle = [self isExpanded] ? -M_PI_4 : 0.0f; + float angle = [self isExpanded] ? self.addRotation : 0.0f; [UIView animateWithDuration:animationDuration animations:^{ self.startButton.transform = CGAffineTransformMakeRotation(angle); + } completion:^(BOOL finished) { + if(self.delegate && [self.delegate respondsToSelector:@selector(awesomeMenuDidFinishAnimationClose:)]){ + [self.delegate awesomeMenuDidFinishAnimationClose:self]; + } }]; - + if ([_delegate respondsToSelector:@selector(awesomeMenu:didSelectIndex:)]) { [_delegate awesomeMenu:self didSelectIndex:item.tag - 1000]; @@ -203,18 +209,18 @@ - (void)AwesomeMenuItemTouchesEnd:(AwesomeMenuItem *)item #pragma mark - Instance methods - (void)setMenuItems:(NSArray *)menuItems -{ +{ if (menuItems == _menuItems) { return; } _menuItems = [menuItems copy]; - - + + // clean subviews - for (UIView *v in self.subviews) + for (UIView *v in self.subviews) { - if (v.tag >= 1000) + if (v.tag >= 1000) { [v removeFromSuperview]; } @@ -246,13 +252,13 @@ - (void)close } - (void)_setMenu { - NSUInteger count = [self.menuItems count]; + NSUInteger count = [self.menuItems count]; for (int i = 0; i < count; i ++) { AwesomeMenuItem *item = [self.menuItems objectAtIndex:i]; item.tag = 1000 + i; item.startPoint = startPoint; - + // avoid overlap if (menuWholeAngle >= M_PI * 2) { menuWholeAngle = menuWholeAngle - menuWholeAngle / count; @@ -262,10 +268,10 @@ - (void)_setMenu { CGPoint nearPoint = CGPointMake(startPoint.x + nearRadius * sinf(i * menuWholeAngle / (count - 1)), startPoint.y - nearRadius * cosf(i * menuWholeAngle / (count - 1))); item.nearPoint = RotateCGPointAroundCenter(nearPoint, startPoint, rotateAngle); CGPoint farPoint = CGPointMake(startPoint.x + farRadius * sinf(i * menuWholeAngle / (count - 1)), startPoint.y - farRadius * cosf(i * menuWholeAngle / (count - 1))); - item.farPoint = RotateCGPointAroundCenter(farPoint, startPoint, rotateAngle); + item.farPoint = RotateCGPointAroundCenter(farPoint, startPoint, rotateAngle); item.center = item.startPoint; item.delegate = self; - [self insertSubview:item belowSubview:self.startButton]; + [self insertSubview:item belowSubview:self.startButton]; } } @@ -275,13 +281,13 @@ - (BOOL)isExpanded } - (void)setExpanded:(BOOL)expanded { - if (expanded) { - [self _setMenu]; + if (expanded) { + [self _setMenu]; if(self.delegate && [self.delegate respondsToSelector:@selector(awesomeMenuWillAnimateOpen:)]){ [self.delegate awesomeMenuWillAnimateOpen:self]; } - } - + } + _expanded = expanded; if(self.delegate && [self.delegate respondsToSelector:@selector(awesomeMenuWillAnimateClose:)]){ [self.delegate awesomeMenuWillAnimateClose:self]; @@ -289,14 +295,14 @@ - (void)setExpanded:(BOOL)expanded // rotate add button if (self.rotateAddButton) { - float angle = [self isExpanded] ? -M_PI_4 : 0.0f; + float angle = [self isExpanded] ? self.addRotation : 0.0f; [UIView animateWithDuration:kAwesomeMenuStartMenuDefaultAnimationDuration animations:^{ self.startButton.transform = CGAffineTransformMakeRotation(angle); }]; } - + // expand or close animation - if (!_timer) + if (!_timer) { _flag = [self isExpanded] ? 0 : ([self.menuItems count] - 1); SEL selector = [self isExpanded] ? @selector(_expandAnimation) : @selector(_closeAnimation); @@ -312,7 +318,7 @@ - (void)setExpanded:(BOOL)expanded - (void)_expandAnimation { - + if (_flag == [self.menuItems count]) { _isAnimating = NO; @@ -320,27 +326,27 @@ - (void)_expandAnimation _timer = nil; return; } - + NSUInteger tag = 1000 + _flag; AwesomeMenuItem *item = (AwesomeMenuItem *)[self viewWithTag:tag]; - + CAKeyframeAnimation *rotateAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; rotateAnimation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:expandRotation],[NSNumber numberWithFloat:0.0f], nil]; rotateAnimation.duration = animationDuration; rotateAnimation.keyTimes = [NSArray arrayWithObjects: - [NSNumber numberWithFloat:.3], - [NSNumber numberWithFloat:.4], nil]; - + [NSNumber numberWithFloat:.3], + [NSNumber numberWithFloat:.4], nil]; + CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; positionAnimation.duration = animationDuration; CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, item.startPoint.x, item.startPoint.y); CGPathAddLineToPoint(path, NULL, item.farPoint.x, item.farPoint.y); - CGPathAddLineToPoint(path, NULL, item.nearPoint.x, item.nearPoint.y); - CGPathAddLineToPoint(path, NULL, item.endPoint.x, item.endPoint.y); + CGPathAddLineToPoint(path, NULL, item.nearPoint.x, item.nearPoint.y); + CGPathAddLineToPoint(path, NULL, item.endPoint.x, item.endPoint.y); positionAnimation.path = path; CGPathRelease(path); - + CAAnimationGroup *animationgroup = [CAAnimationGroup animation]; animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, rotateAnimation, nil]; animationgroup.duration = animationDuration; @@ -350,12 +356,12 @@ - (void)_expandAnimation if(_flag == [self.menuItems count] - 1){ [animationgroup setValue:@"firstAnimation" forKey:@"id"]; } - + [item.layer addAnimation:animationgroup forKey:@"Expand"]; item.center = item.endPoint; - + _flag ++; - + } - (void)_closeAnimation @@ -367,27 +373,27 @@ - (void)_closeAnimation _timer = nil; return; } - + NSUInteger tag = 1000 + _flag; - AwesomeMenuItem *item = (AwesomeMenuItem *)[self viewWithTag:tag]; - + AwesomeMenuItem *item = (AwesomeMenuItem *)[self viewWithTag:tag]; + CAKeyframeAnimation *rotateAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; rotateAnimation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f],[NSNumber numberWithFloat:closeRotation],[NSNumber numberWithFloat:0.0f], nil]; rotateAnimation.duration = animationDuration; rotateAnimation.keyTimes = [NSArray arrayWithObjects: - [NSNumber numberWithFloat:.0], + [NSNumber numberWithFloat:.0], [NSNumber numberWithFloat:.4], - [NSNumber numberWithFloat:.5], nil]; - + [NSNumber numberWithFloat:.5], nil]; + CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; positionAnimation.duration = animationDuration; CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, item.endPoint.x, item.endPoint.y); CGPathAddLineToPoint(path, NULL, item.farPoint.x, item.farPoint.y); - CGPathAddLineToPoint(path, NULL, item.startPoint.x, item.startPoint.y); + CGPathAddLineToPoint(path, NULL, item.startPoint.x, item.startPoint.y); positionAnimation.path = path; CGPathRelease(path); - + CAAnimationGroup *animationgroup = [CAAnimationGroup animation]; animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, rotateAnimation, nil]; animationgroup.duration = animationDuration; @@ -397,7 +403,7 @@ - (void)_closeAnimation if(_flag == 0){ [animationgroup setValue:@"lastAnimation" forKey:@"id"]; } - + [item.layer addAnimation:animationgroup forKey:@"Close"]; item.center = item.startPoint; @@ -419,14 +425,14 @@ - (CAAnimationGroup *)_blowupAnimationAtPoint:(CGPoint)p { CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; positionAnimation.values = [NSArray arrayWithObjects:[NSValue valueWithCGPoint:p], nil]; - positionAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.3], nil]; - + positionAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.3], nil]; + CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform"]; scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(3, 3, 1)]; - + CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; opacityAnimation.toValue = [NSNumber numberWithFloat:0.0f]; - + CAAnimationGroup *animationgroup = [CAAnimationGroup animation]; animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, scaleAnimation, opacityAnimation, nil]; animationgroup.duration = animationDuration; @@ -439,14 +445,14 @@ - (CAAnimationGroup *)_shrinkAnimationAtPoint:(CGPoint)p { CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; positionAnimation.values = [NSArray arrayWithObjects:[NSValue valueWithCGPoint:p], nil]; - positionAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.3], nil]; - + positionAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.3], nil]; + CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform"]; scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(.01, .01, 1)]; - + CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; opacityAnimation.toValue = [NSNumber numberWithFloat:0.0f]; - + CAAnimationGroup *animationgroup = [CAAnimationGroup animation]; animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, scaleAnimation, opacityAnimation, nil]; animationgroup.duration = animationDuration;