扩展QuadCurveMenu,实现了八个方向上的弹出菜单

最近在看一些开源项目,其中有一个弹出菜单QuadCurveMenu觉得挺不错,可惜只可以向右上角弹出菜单,于是就修改了下,实现了八个方向的弹出菜单,现在发上来供大家批评指正。

[cpp]  view plain copy
  1. //  
  2. //  QuadCurveMenu.h  
  3. //  AwesomeMenu  
  4. //  
  5. //  Created by Levey on 11/30/11.  
  6. //  Copyright (c) 2011 Lunaapp.com. All rights reserved.  
  7. //  
  8.   
  9. #import <UIKit/UIKit.h>  
  10. #import "QuadCurveMenuItem.h"  
  11.   
  12. @protocol QuadCurveMenuDelegate;  
  13.   
  14. //defult type is like this  
  15. /* 
  16.  *       O 
  17.  *           O 
  18.  *              O  
  19.  *                O    
  20.  *       0         O      
  21.  */  
  22. typedef enum  
  23. {  
  24.     QuadCurveMenuTypeUpAndRight = 0,                   
  25.     QuadCurveMenuTypeUpAndLeft,  
  26.     QuadCurveMenuTypeDownAndRight,  
  27.     QuadCurveMenuTypeDownAndLeft,  
  28.     QuadCurveMenuTypeUp,  
  29.     QuadCurveMenuTypeDown,  
  30.     QuadCurveMenuTypeLeft,  
  31.     QuadCurveMenuTypeRight,  
  32.     QuadCurveMenuTypeDefault = QuadCurveMenuTypeUpAndRight  
  33. } QuadCureMenuType;  
  34.   
  35. @interface QuadCurveMenu : UIView <QuadCurveMenuItemDelegate>  
  36. {  
  37.     NSArray *_menusArray;  
  38.     int _flag;  
  39.     NSTimer *_timer;  
  40.     QuadCurveMenuItem *_addButton;  
  41.     QuadCureMenuType _type;  
  42.     id<QuadCurveMenuDelegate> _delegate;  
  43.       
  44.     CGPoint _startPoint;  
  45.   
  46. }  
  47. @property (nonatomic, copy) NSArray *menusArray;  
  48. @property (nonatomic) QuadCureMenuType type;  
  49. @property (nonatomic, getter = isExpanding)     BOOL expanding;  
  50. @property (nonatomic, assign) id<QuadCurveMenuDelegate> delegate;  
  51. - (id)initWithFrame:(CGRect)frame menus:(NSArray *)aMenusArray;  
  52. - (void) setType:(QuadCureMenuType)type;  
  53. - (void) setStartPoint:(CGPoint) startpoint;  
  54. @end  
  55.   
  56. @protocol QuadCurveMenuDelegate <NSObject>  
  57. - (void)quadCurveMenu:(QuadCurveMenu *)menu didSelectIndex:(NSInteger)idx;  
  58. @end  

[cpp]  view plain copy
  1. //  
  2. //  QuadCurveMenu.m  
  3. //  AwesomeMenu  
  4. //  
  5. //  Created by Levey on 11/30/11.  
  6. //  Copyright (c) 2011 Lunaapp.com. All rights reserved.  
  7. //  
  8.   
  9. #import "QuadCurveMenu.h"  
  10. #import <QuartzCore/QuartzCore.h>  
  11.   
  12. #define NEARRADIUS 130.0f  
  13. #define ENDRADIUS 140.0f  
  14. #define FARRADIUS 160.0f  
  15. #define BETWEENADIUS 50.0f  
  16. #define STARTPOINT CGPointMake(100, 130)  
  17. #define TIMEOFFSET 0.05f  
  18.   
  19.   
  20. @interface QuadCurveMenu ()  
  21. - (void)_expand;  
  22. - (void)_close;  
  23. - (CAAnimationGroup *)_blowupAnimationAtPoint:(CGPoint)p;  
  24. - (CAAnimationGroup *)_shrinkAnimationAtPoint:(CGPoint)p;  
  25. @end  
  26.   
  27. @implementation QuadCurveMenu  
  28. @synthesize expanding = _expanding;  
  29. @synthesize delegate = _delegate;  
  30. @synthesize menusArray = _menusArray;  
  31. @synthesize type = _type;  
  32.   
  33.   
  34. #pragma mark - initialization & cleaning up  
  35. - (id)initWithFrame:(CGRect)frame menus:(NSArray *)aMenusArray  
  36. {  
  37.     self = [super initWithFrame:frame];  
  38.     if (self) {  
  39.         self.backgroundColor = [UIColor clearColor];  
  40.           
  41.         _startPoint = STARTPOINT;  
  42.         _menusArray = [aMenusArray copy];  
  43.           
  44.         // add the menu buttons  
  45.         int count = [_menusArray count];  
  46.         for (int i = 0; i < count; i ++)  
  47.         {  
  48.             QuadCurveMenuItem *item = [_menusArray objectAtIndex:i];  
  49.             item.tag = 1000 + i;  
  50.             item.startPoint = STARTPOINT;  
  51.             item.endPoint = CGPointMake(_startPoint.x + ENDRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - ENDRADIUS * cosf(i * M_PI_2 / (count - 1)));  
  52.             item.nearPoint = CGPointMake(_startPoint.x + NEARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - NEARRADIUS * cosf(i * M_PI_2 / (count - 1)));  
  53.             item.farPoint = CGPointMake(_startPoint.x + FARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - FARRADIUS * cosf(i * M_PI_2 / (count - 1)));  
  54.             item.center = item.startPoint;  
  55.             item.delegate = self;  
  56.             [self addSubview:item];  
  57.         }  
  58.           
  59.         // add the "Add" Button.  
  60.         _addButton = [[QuadCurveMenuItem alloc] initWithImage:[UIImage imageNamed:@"story-add-button.png"]  
  61.                                        highlightedImage:[UIImage imageNamed:@"story-add-button-pressed.png"]   
  62.                                            ContentImage:[UIImage imageNamed:@"story-add-plus.png"]   
  63.                                 highlightedContentImage:[UIImage imageNamed:@"story-add-plus-pressed.png"]];  
  64.         _addButton.delegate = self;  
  65.         _addButton.center = _startPoint;  
  66.         [self addSubview:_addButton];  
  67.     }  
  68.     return self;  
  69. }  
  70.   
  71.   
  72. - (void) setType:(QuadCureMenuType)type  
  73. {  
  74.     _type = type;  
  75.     int dx =1;   
  76.     int dy =1;  
  77.     BOOL isTwoDirctions = YES;  
  78.     
  79.     if (_menusArray !=nil) {  
  80.     
  81.         switch (type) {  
  82.             case QuadCurveMenuTypeUpAndRight:  
  83.                 break;  
  84.             case QuadCurveMenuTypeUpAndLeft:  
  85.                 dx = -1;  
  86.                 break;  
  87.             case QuadCurveMenuTypeDownAndRight:  
  88.                 dy = -1;  
  89.                 break;  
  90.             case QuadCurveMenuTypeDownAndLeft:  
  91.                 dy = dx = -1;  
  92.                 break;  
  93.             case QuadCurveMenuTypeUp:  
  94.                 isTwoDirctions = NO; dx = 0; dy = -1;  
  95.                 break;  
  96.             case QuadCurveMenuTypeDown:  
  97.                 isTwoDirctions = NO; dx = 0; dy = 1;  
  98.                 break;  
  99.             case QuadCurveMenuTypeLeft:  
  100.                 isTwoDirctions = NO; dx = -1; dy = 0;  
  101.                 break;  
  102.             case QuadCurveMenuTypeRight:  
  103.                 isTwoDirctions = NO; dx = 1; dy = 0;  
  104.             default:  
  105.                 break;  
  106.         }  
  107.           
  108.         int count = [_menusArray count];  
  109.         for (int i = 0; i < count; i ++)  
  110.         {  
  111.             QuadCurveMenuItem *item = [_menusArray objectAtIndex:i];  
  112.             item.startPoint = _startPoint;  
  113.             if (isTwoDirctions) {  
  114.                 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)));  
  115.                 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)));  
  116.                 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)));  
  117.             }else  
  118.             {  
  119.                 item.endPoint = CGPointMake(_startPoint.x + dx * i * BETWEENADIUS , _startPoint.y + dy * i * BETWEENADIUS);  
  120.                 item.nearPoint = CGPointMake(_startPoint.x +dx * i * (BETWEENADIUS - 15), _startPoint.y + dy * i * (BETWEENADIUS - 15));  
  121.                 item.farPoint = CGPointMake(_startPoint.x + dx * i * (BETWEENADIUS + 20), _startPoint.y + dy * i * (BETWEENADIUS + 20));  
  122.               
  123.             }  
  124.             item.center = item.startPoint;  
  125.              
  126.         }  
  127.   
  128.     }  
  129. }  
  130.   
  131. - (void) setStartPoint:(CGPoint) startpoint  
  132. {  
  133.     _startPoint = startpoint;  
  134.      _addButton.center = _startPoint;  
  135.     [self setType: _type];  
  136. };  
  137.   
  138. - (void)dealloc  
  139. {  
  140.     [_addButton release];  
  141.     [_menusArray release];  
  142.     [super dealloc];  
  143. }  
  144.   
  145.                                  
  146. #pragma mark - UIView's methods  
  147. - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event  
  148. {  
  149.     // if the menu state is expanding, everywhere can be touch  
  150.     // otherwise, only the add button are can be touch  
  151.     if (YES == _expanding)   
  152.     {  
  153.         return YES;  
  154.     }  
  155.     else  
  156.     {  
  157.         return CGRectContainsPoint(_addButton.frame, point);  
  158.     }  
  159. }  
  160.   
  161. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  
  162. {  
  163.     self.expanding = !self.isExpanding;  
  164. }  
  165.   
  166. #pragma mark - QuadCurveMenuItem delegates  
  167. - (void)quadCurveMenuItemTouchesBegan:(QuadCurveMenuItem *)item  
  168. {  
  169.     if (item == _addButton)   
  170.     {  
  171.         self.expanding = !self.isExpanding;  
  172.     }  
  173. }  
  174. - (void)quadCurveMenuItemTouchesEnd:(QuadCurveMenuItem *)item  
  175. {  
  176.     // exclude the "add" button  
  177.     if (item == _addButton)   
  178.     {  
  179.         return;  
  180.     }  
  181.     // blowup the selected menu button  
  182.     CAAnimationGroup *blowup = [self _blowupAnimationAtPoint:item.center];  
  183.     [item.layer addAnimation:blowup forKey:@"blowup"];  
  184.     item.center = item.startPoint;  
  185.       
  186.     // shrink other menu buttons  
  187.     for (int i = 0; i < [_menusArray count]; i ++)  
  188.     {  
  189.         QuadCurveMenuItem *otherItem = [_menusArray objectAtIndex:i];  
  190.         CAAnimationGroup *shrink = [self _shrinkAnimationAtPoint:otherItem.center];  
  191.         if (otherItem.tag == item.tag) {  
  192.             continue;  
  193.         }  
  194.         [otherItem.layer addAnimation:shrink forKey:@"shrink"];  
  195.   
  196.         otherItem.center = otherItem.startPoint;  
  197.     }  
  198.     _expanding = NO;  
  199.       
  200.     // rotate "add" button  
  201.     float angle = self.isExpanding ? -M_PI_4 : 0.0f;  
  202.     [UIView animateWithDuration:0.2f animations:^{  
  203.         _addButton.transform = CGAffineTransformMakeRotation(angle);  
  204.     }];  
  205.       
  206.     if ([_delegate respondsToSelector:@selector(quadCurveMenu:didSelectIndex:)])  
  207.     {  
  208.         [_delegate quadCurveMenu:self didSelectIndex:item.tag - 1000];  
  209.     }  
  210. }  
  211.   
  212. #pragma mark - instant methods  
  213. - (void)setMenusArray:(NSArray *)aMenusArray  
  214. {  
  215.     if (aMenusArray == _menusArray)  
  216.     {  
  217.         return;  
  218.     }  
  219.     [_menusArray release];  
  220.     _menusArray = [aMenusArray copy];  
  221.       
  222.       
  223.     // clean subviews  
  224.     for (UIView *v in self.subviews)   
  225.     {  
  226.         if (v.tag >= 1000)   
  227.         {  
  228.             [v removeFromSuperview];  
  229.         }  
  230.     }  
  231.       
  232.     // add the menu buttons  
  233.     int count = [_menusArray count];  
  234.     for (int i = 0; i < count; i ++)  
  235.     {  
  236.         QuadCurveMenuItem *item = [_menusArray objectAtIndex:i];  
  237.         item.tag = 1000 + i;  
  238.         item.startPoint = _startPoint;  
  239.         item.endPoint = CGPointMake(_startPoint.x + ENDRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - ENDRADIUS * cosf(i * M_PI_2 / (count - 1)));  
  240.         item.nearPoint = CGPointMake(_startPoint.x + NEARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - NEARRADIUS * cosf(i * M_PI_2 / (count - 1)));  
  241.         item.farPoint = CGPointMake(_startPoint.x + FARRADIUS * sinf(i * M_PI_2 / (count - 1)), _startPoint.y - FARRADIUS * cosf(i * M_PI_2 / (count - 1)));  
  242.         item.center = item.startPoint;  
  243.         item.delegate = self;  
  244.         [self addSubview:item];  
  245.     }  
  246. }  
  247. - (BOOL)isExpanding  
  248. {  
  249.     return _expanding;  
  250. }  
  251. - (void)setExpanding:(BOOL)expanding  
  252. {  
  253.     _expanding = expanding;      
  254.       
  255.     // rotate add button  
  256.     float angle = self.isExpanding ? -M_PI_4 : 0.0f;  
  257.     [UIView animateWithDuration:0.2f animations:^{  
  258.         _addButton.transform = CGAffineTransformMakeRotation(angle);  
  259.     }];  
  260.       
  261.     // expand or close animation  
  262.     if (!_timer)   
  263.     {  
  264.         _flag = self.isExpanding ? 0 : 5;  
  265.         SEL selector = self.isExpanding ? @selector(_expand) : @selector(_close);  
  266.         _timer = [[NSTimer scheduledTimerWithTimeInterval:TIMEOFFSET target:self selector:selector userInfo:nil repeats:YES] retain];  
  267.     }  
  268. }  
  269. #pragma mark - private methods  
  270. - (void)_expand  
  271. {  
  272.     if (_flag == 6)  
  273.     {  
  274.         [_timer invalidate];  
  275.         [_timer release];  
  276.         _timer = nil;  
  277.         return;  
  278.     }  
  279.       
  280.     int tag = 1000 + _flag;  
  281.     QuadCurveMenuItem *item = (QuadCurveMenuItem *)[self viewWithTag:tag];  
  282.       
  283.     CAKeyframeAnimation *rotateAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];  
  284.     rotateAnimation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:M_PI],[NSNumber numberWithFloat:0.0f], nil];  
  285.     rotateAnimation.duration = 0.5f;  
  286.     rotateAnimation.keyTimes = [NSArray arrayWithObjects:  
  287.                                 [NSNumber numberWithFloat:.3],   
  288.                                 [NSNumber numberWithFloat:.4], nil];   
  289.       
  290.     CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];  
  291.     positionAnimation.duration = 0.5f;  
  292.     CGMutablePathRef path = CGPathCreateMutable();  
  293.     CGPathMoveToPoint(path, NULL, item.startPoint.x, item.startPoint.y);  
  294.     CGPathAddLineToPoint(path, NULL, item.farPoint.x, item.farPoint.y);  
  295.     CGPathAddLineToPoint(path, NULL, item.nearPoint.x, item.nearPoint.y);   
  296.     CGPathAddLineToPoint(path, NULL, item.endPoint.x, item.endPoint.y);   
  297.     positionAnimation.path = path;  
  298.     CGPathRelease(path);  
  299.       
  300.     CAAnimationGroup *animationgroup = [CAAnimationGroup animation];  
  301.     animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, rotateAnimation, nil];  
  302.     animationgroup.duration = 0.5f;  
  303.     animationgroup.fillMode = kCAFillModeForwards;  
  304.     animationgroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];  
  305.     [item.layer addAnimation:animationgroup forKey:@"Expand"];  
  306.     item.center = item.endPoint;  
  307.       
  308.     _flag ++;  
  309.       
  310. }  
  311.   
  312. - (void)_close  
  313. {  
  314.     if (_flag == -1)  
  315.     {  
  316.         [_timer invalidate];  
  317.         [_timer release];  
  318.         _timer = nil;  
  319.         return;  
  320.     }  
  321.       
  322.     int tag = 1000 + _flag;  
  323.      QuadCurveMenuItem *item = (QuadCurveMenuItem *)[self viewWithTag:tag];  
  324.       
  325.     CAKeyframeAnimation *rotateAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];  
  326.     rotateAnimation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f],[NSNumber numberWithFloat:M_PI * 2],[NSNumber numberWithFloat:0.0f], nil];  
  327.     rotateAnimation.duration = 0.5f;  
  328.     rotateAnimation.keyTimes = [NSArray arrayWithObjects:  
  329.                                 [NSNumber numberWithFloat:.0],   
  330.                                 [NSNumber numberWithFloat:.4],  
  331.                                 [NSNumber numberWithFloat:.5], nil];   
  332.           
  333.     CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];  
  334.     positionAnimation.duration = 0.5f;  
  335.     CGMutablePathRef path = CGPathCreateMutable();  
  336.     CGPathMoveToPoint(path, NULL, item.endPoint.x, item.endPoint.y);  
  337.     CGPathAddLineToPoint(path, NULL, item.farPoint.x, item.farPoint.y);  
  338.     CGPathAddLineToPoint(path, NULL, item.startPoint.x, item.startPoint.y);   
  339.     positionAnimation.path = path;  
  340.     CGPathRelease(path);  
  341.       
  342.     CAAnimationGroup *animationgroup = [CAAnimationGroup animation];  
  343.     animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, rotateAnimation, nil];  
  344.     animationgroup.duration = 0.5f;  
  345.     animationgroup.fillMode = kCAFillModeForwards;  
  346.     animationgroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];  
  347.     [item.layer addAnimation:animationgroup forKey:@"Close"];  
  348.     item.center = item.startPoint;  
  349.     _flag --;  
  350. }  
  351.   
  352. - (CAAnimationGroup *)_blowupAnimationAtPoint:(CGPoint)p  
  353. {  
  354.     CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];  
  355.     positionAnimation.values = [NSArray arrayWithObjects:[NSValue valueWithCGPoint:p], nil];  
  356.     positionAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.3], nil];   
  357.       
  358.     CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];  
  359.     scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(3, 3, 1)];  
  360.       
  361.     CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];  
  362.     opacityAnimation.toValue  = [NSNumber numberWithFloat:0.0f];  
  363.       
  364.     CAAnimationGroup *animationgroup = [CAAnimationGroup animation];  
  365.     animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, scaleAnimation, opacityAnimation, nil];  
  366.     animationgroup.duration = 0.3f;  
  367.     animationgroup.fillMode = kCAFillModeForwards;  
  368.   
  369.     return animationgroup;  
  370. }  
  371.   
  372. - (CAAnimationGroup *)_shrinkAnimationAtPoint:(CGPoint)p  
  373. {  
  374.     CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];  
  375.     positionAnimation.values = [NSArray arrayWithObjects:[NSValue valueWithCGPoint:p], nil];  
  376.     positionAnimation.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:.3], nil];   
  377.       
  378.     CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];  
  379.     scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(.01, .01, 1)];  
  380.       
  381.     CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];  
  382.     opacityAnimation.toValue  = [NSNumber numberWithFloat:0.0f];  
  383.       
  384.     CAAnimationGroup *animationgroup = [CAAnimationGroup animation];  
  385.     animationgroup.animations = [NSArray arrayWithObjects:positionAnimation, scaleAnimation, opacityAnimation, nil];  
  386.     animationgroup.duration = 0.3f;  
  387.     animationgroup.fillMode = kCAFillModeForwards;  
  388.       
  389.     return animationgroup;  
  390. }  
  391.   
  392.   
  393. @end  

运行截图:

扩展QuadCurveMenu,实现了八个方向上的弹出菜单_第1张图片扩展QuadCurveMenu,实现了八个方向上的弹出菜单_第2张图片DEMO下载地址:http://download.csdn.net/detail/toss156/4164935

你可能感兴趣的:(扩展QuadCurveMenu,实现了八个方向上的弹出菜单)