最近在看一些开源项目,其中有一个弹出菜单QuadCurveMenu觉得挺不错,可惜只可以向右上角弹出菜单,于是就修改了下,实现了八个方向的弹出菜单,现在发上来供大家批评指正。
// // QuadCurveMenu.h // AwesomeMenu // // Created by Levey on 11/30/11. // Copyright (c) 2011 Lunaapp.com. All rights reserved. // #import <UIKit/UIKit.h> #import "QuadCurveMenuItem.h" @protocol QuadCurveMenuDelegate; //defult type is like this /* * O * O * O * O * 0 O */ typedef enum { QuadCurveMenuTypeUpAndRight = 0, QuadCurveMenuTypeUpAndLeft, QuadCurveMenuTypeDownAndRight, QuadCurveMenuTypeDownAndLeft, QuadCurveMenuTypeUp, QuadCurveMenuTypeDown, QuadCurveMenuTypeLeft, QuadCurveMenuTypeRight, QuadCurveMenuTypeDefault = QuadCurveMenuTypeUpAndRight } QuadCureMenuType; @interface QuadCurveMenu : UIView <QuadCurveMenuItemDelegate> { NSArray *_menusArray; int _flag; NSTimer *_timer; QuadCurveMenuItem *_addButton; QuadCureMenuType _type; id<QuadCurveMenuDelegate> _delegate; CGPoint _startPoint; } @property (nonatomic, copy) NSArray *menusArray; @property (nonatomic) QuadCureMenuType type; @property (nonatomic, getter = isExpanding) BOOL expanding; @property (nonatomic, assign) id<QuadCurveMenuDelegate> delegate; - (id)initWithFrame:(CGRect)frame menus:(NSArray *)aMenusArray; - (void) setType:(QuadCureMenuType)type; - (void) setStartPoint:(CGPoint) startpoint; @end @protocol QuadCurveMenuDelegate <NSObject> - (void)quadCurveMenu:(QuadCurveMenu *)menu didSelectIndex:(NSInteger)idx; @end
// // QuadCurveMenu.m // AwesomeMenu // // Created by Levey on 11/30/11. // Copyright (c) 2011 Lunaapp.com. All rights reserved. // #import "QuadCurveMenu.h" #import <QuartzCore/QuartzCore.h> #define NEARRADIUS 130.0f #define ENDRADIUS 140.0f #define FARRADIUS 160.0f #define BETWEENADIUS 50.0f #define STARTPOINT CGPointMake(100, 130) #define TIMEOFFSET 0.05f @interface QuadCurveMenu () - (void)_expand; - (void)_close; - (CAAnimationGroup *)_blowupAnimationAtPoint:(CGPoint)p; - (CAAnimationGroup *)_shrinkAnimationAtPoint:(CGPoint)p; @end @implementation QuadCurveMenu @synthesize expanding = _expanding; @synthesize delegate = _delegate; @synthesize menusArray = _menusArray; @synthesize type = _type; #pragma mark - initialization & cleaning up - (id)initWithFrame:(CGRect)frame menus:(NSArray *)aMenusArray { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor clearColor]; _startPoint = STARTPOINT; _menusArray = [aMenusArray copy]; // add the menu buttons int count = [_menusArray count]; for (int i = 0; i < count; i ++) { QuadCurveMenuItem *item = [_menusArray objectAtIndex:i]; item.tag = 1000 + i; item.startPoint = STARTPOINT; item.endPoint = CGPointMake(_startPoint.x + ENDRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - ENDRADIUS * cosf(i * M_PI_2 / (count - 1))); item.nearPoint = CGPointMake(_startPoint.x + NEARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - NEARRADIUS * cosf(i * M_PI_2 / (count - 1))); item.farPoint = CGPointMake(_startPoint.x + FARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - FARRADIUS * cosf(i * M_PI_2 / (count - 1))); item.center = item.startPoint; item.delegate = self; [self addSubview:item]; } // add the "Add" Button. _addButton = [[QuadCurveMenuItem alloc] initWithImage:[UIImage imageNamed:@"story-add-button.png"] highlightedImage:[UIImage imageNamed:@"story-add-button-pressed.png"] ContentImage:[UIImage imageNamed:@"story-add-plus.png"] highlightedContentImage:[UIImage imageNamed:@"story-add-plus-pressed.png"]]; _addButton.delegate = self; _addButton.center = _startPoint; [self addSubview:_addButton]; } return self; } - (void) setType:(QuadCureMenuType)type { _type = type; int dx =1; int dy =1; BOOL isTwoDirctions = YES; if (_menusArray !=nil) { switch (type) { case QuadCurveMenuTypeUpAndRight: break; case QuadCurveMenuTypeUpAndLeft: dx = -1; break; case QuadCurveMenuTypeDownAndRight: dy = -1; break; case QuadCurveMenuTypeDownAndLeft: dy = dx = -1; break; case QuadCurveMenuTypeUp: isTwoDirctions = NO; dx = 0; dy = -1; break; case QuadCurveMenuTypeDown: isTwoDirctions = NO; dx = 0; dy = 1; break; case QuadCurveMenuTypeLeft: isTwoDirctions = NO; dx = -1; dy = 0; break; case QuadCurveMenuTypeRight: isTwoDirctions = NO; dx = 1; dy = 0; default: break; } int count = [_menusArray count]; for (int i = 0; i < count; i ++) { QuadCurveMenuItem *item = [_menusArray objectAtIndex:i]; item.startPoint = _startPoint; if (isTwoDirctions) { item.endPoint = CGPointMake(_startPoint.x + dx * ENDRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y -dy * ENDRADIUS * cosf(i * M_PI_2 / (count - 1))); item.nearPoint = CGPointMake(_startPoint.x +dx * NEARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y -dy * NEARRADIUS * cosf(i * M_PI_2 / (count - 1))); item.farPoint = CGPointMake(_startPoint.x + dx * FARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y -dy * FARRADIUS * cosf(i * M_PI_2 / (count - 1))); }else { item.endPoint = CGPointMake(_startPoint.x + dx * i * BETWEENADIUS , _startPoint.y + dy * i * BETWEENADIUS); item.nearPoint = CGPointMake(_startPoint.x +dx * i * (BETWEENADIUS - 15), _startPoint.y + dy * i * (BETWEENADIUS - 15)); item.farPoint = CGPointMake(_startPoint.x + dx * i * (BETWEENADIUS + 20), _startPoint.y + dy * i * (BETWEENADIUS + 20)); } item.center = item.startPoint; } } } - (void) setStartPoint:(CGPoint) startpoint { _startPoint = startpoint; _addButton.center = _startPoint; [self setType: _type]; }; - (void)dealloc { [_addButton release]; [_menusArray release]; [super dealloc]; } #pragma mark - UIView's methods - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { // if the menu state is expanding, everywhere can be touch // otherwise, only the add button are can be touch if (YES == _expanding) { return YES; } else { return CGRectContainsPoint(_addButton.frame, point); } } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { self.expanding = !self.isExpanding; } #pragma mark - QuadCurveMenuItem delegates - (void)quadCurveMenuItemTouchesBegan:(QuadCurveMenuItem *)item { if (item == _addButton) { self.expanding = !self.isExpanding; } } - (void)quadCurveMenuItemTouchesEnd:(QuadCurveMenuItem *)item { // exclude the "add" button if (item == _addButton) { return; } // blowup the selected menu button 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 < [_menusArray count]; i ++) { QuadCurveMenuItem *otherItem = [_menusArray objectAtIndex:i]; CAAnimationGroup *shrink = [self _shrinkAnimationAtPoint:otherItem.center]; if (otherItem.tag == item.tag) { continue; } [otherItem.layer addAnimation:shrink forKey:@"shrink"]; otherItem.center = otherItem.startPoint; } _expanding = NO; // rotate "add" button float angle = self.isExpanding ? -M_PI_4 : 0.0f; [UIView animateWithDuration:0.2f animations:^{ _addButton.transform = CGAffineTransformMakeRotation(angle); }]; if ([_delegate respondsToSelector:@selector(quadCurveMenu:didSelectIndex:)]) { [_delegate quadCurveMenu:self didSelectIndex:item.tag - 1000]; } } #pragma mark - instant methods - (void)setMenusArray:(NSArray *)aMenusArray { if (aMenusArray == _menusArray) { return; } [_menusArray release]; _menusArray = [aMenusArray copy]; // clean subviews for (UIView *v in self.subviews) { if (v.tag >= 1000) { [v removeFromSuperview]; } } // add the menu buttons int count = [_menusArray count]; for (int i = 0; i < count; i ++) { QuadCurveMenuItem *item = [_menusArray objectAtIndex:i]; item.tag = 1000 + i; item.startPoint = _startPoint; item.endPoint = CGPointMake(_startPoint.x + ENDRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - ENDRADIUS * cosf(i * M_PI_2 / (count - 1))); item.nearPoint = CGPointMake(_startPoint.x + NEARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - NEARRADIUS * cosf(i * M_PI_2 / (count - 1))); item.farPoint = CGPointMake(_startPoint.x + FARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - FARRADIUS * cosf(i * M_PI_2 / (count - 1))); item.center = item.startPoint; item.delegate = self; [self addSubview:item]; } } - (BOOL)isExpanding { return _expanding; } - (void)setExpanding:(BOOL)expanding { _expanding = expanding; // rotate add button float angle = self.isExpanding ? -M_PI_4 : 0.0f; [UIView animateWithDuration:0.2f animations:^{ _addButton.transform = CGAffineTransformMakeRotation(angle); }]; // expand or close animation if (!_timer) { _flag = self.isExpanding ? 0 : 5; SEL selector = self.isExpanding ? @selector(_expand) : @selector(_close); _timer = [[NSTimer scheduledTimerWithTimeInterval:TIMEOFFSET target:self selector:selector userInfo:nil repeats:YES] retain]; } } #pragma mark - private methods - (void)_expand { if (_flag == 6) { [_timer invalidate]; [_timer release]; _timer = nil; return; } int tag = 1000 + _flag; QuadCurveMenuItem *item = (QuadCurveMenuItem *)[self viewWithTag:tag]; CAKeyframeAnimation *rotateAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; rotateAnimation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:M_PI],[NSNumber numberWithFloat:0.0f], nil]; rotateAnimation.duration = 0.5f; rotateAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.3], [NSNumber numberWithFloat:.4], nil]; CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; positionAnimation.duration = 0.5f; 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); positionAnimation.path = path; CGPathRelease(path); CAAnimationGroup *animationgroup = [CAAnimationGroup animation]; animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, rotateAnimation, nil]; animationgroup.duration = 0.5f; animationgroup.fillMode = kCAFillModeForwards; animationgroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; [item.layer addAnimation:animationgroup forKey:@"Expand"]; item.center = item.endPoint; _flag ++; } - (void)_close { if (_flag == -1) { [_timer invalidate]; [_timer release]; _timer = nil; return; } int tag = 1000 + _flag; QuadCurveMenuItem *item = (QuadCurveMenuItem *)[self viewWithTag:tag]; CAKeyframeAnimation *rotateAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; rotateAnimation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f],[NSNumber numberWithFloat:M_PI * 2],[NSNumber numberWithFloat:0.0f], nil]; rotateAnimation.duration = 0.5f; rotateAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.0], [NSNumber numberWithFloat:.4], [NSNumber numberWithFloat:.5], nil]; CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; positionAnimation.duration = 0.5f; 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); positionAnimation.path = path; CGPathRelease(path); CAAnimationGroup *animationgroup = [CAAnimationGroup animation]; animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, rotateAnimation, nil]; animationgroup.duration = 0.5f; animationgroup.fillMode = kCAFillModeForwards; animationgroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; [item.layer addAnimation:animationgroup forKey:@"Close"]; item.center = item.startPoint; _flag --; } - (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]; 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 = 0.3f; animationgroup.fillMode = kCAFillModeForwards; return animationgroup; } - (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]; 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 = 0.3f; animationgroup.fillMode = kCAFillModeForwards; return animationgroup; } @end
运行截图:
DEMO下载地址:http://download.csdn.net/detail/toss156/4164935