QuadCurveMenu 是一个与 Path 应用程序的菜单相同风格的菜单。
这是我基于 levey 的 AwesomeMenu 的分支。我提出了一项拉取请求,但这并不是原始作者的初衷。这个分支有一些显著的不同之处,我在 拉取请求 中概述了这些不同。
我真的喜欢这个菜单,并希望使用任何数据源(不仅仅是数组),更多的触摸事件,以及能够操作图像和动画的能力。我还希望菜单项能够持有一些数据对象,这样我就可以在选中时存储和检索数据,而不是依赖于索引。
最终,这是一个更模块化的库,允许您为菜单定义新功能,而无需撕裂现有库的内容。
QuadCurveMenu 被定义在多个文件中,以分离关注点并使代码更易于维护和清晰。这确实增加了当代码包含在项目中时的负担。
将项目转换为 ARC
示例中的 AppDelegate 不再负责菜单,并创建了一个示例视图控制器。
菜单将为 willExpand
、didExpand
、willClose
和 didClose
生成委托事件。
菜单在扩展之前会请求委托的 shouldExpand
,在关闭之前请求 shouldClose
。
菜单将生成触摸(didTapMenu
)和长按(didLongPressMenu
)事件。
菜单从数据源委托中进行填充
菜单由 MenuItemFactory 进行设计
菜单由可定义的动画组成,用于扩展、关闭、选中、未选中
菜单动画现在在其自己的独立类中
菜单可以显示以径向、线性或自定义样式的菜单项
菜单项将为触摸(didTapMenuItem
)和长按(didLongPressMenuItem
)生成事件
菜单项将自动进行宝石化(AGMedallionView),因此无需创建自定义的 宝石化 图像。
菜单项由 MenuItemFactory 进行设计
菜单项包含数据对象
QuadCurveMenu 定义了一个简单的初始化器,它生成一个径向菜单,360 度,在给定的帧内居中,显示每个元素提供的数组中的菜单项。
@implementation AwesomeViewController
- (void)viewDidLoad {
[super viewDidLoad]
NSArray *menuItemArray = [NSArray arrayWithObjects:@"1",@"2",nil];
QuadCurveMenu *menu = [[QuadCurveMenu alloc] initWithFrame:self.view.bounds withArray:menuItemArray];
[self.view addSubview:menu];
}
@end
您可能会发现使用 NSArray 对数据源的限制作出可以有自定义数据源的菜单。
首先,您定义一个数据源,或者使用符合 QuadCurveDataSourceDelegate
协议现成的数据源。
默认情况下,当您使用数组实现时,它使用
QuadCurveDefaultDataSource
,它只是对 NSArray 进行了包装。
@interface AwesomeDataSource : NSObject <QuadCurveDataSourceDelegate> {
NSMutableArray *dataItems;
}
@end
@implementation AwesomeDataSource
- (id)init {
self = [super init];
if (self) {
dataItems = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4",@"5",@"6", nil];
}
return self;
}
#pragma mark - QuadCurveDataSourceDelegate Adherence
- (int)numberOfMenuItems {
return [dataItems count];
}
- (id)dataObjectAtIndex:(NSInteger)itemIndex {
return [dataItems objectAtIndex:itemIndex];
}
使用自定义数据源创建 QuadCurveMenu
@implementation AwesomeViewController
- (void)viewDidLoad {
[super viewDidLoad]
AwesomeDataSource *dataSource = [[AwesomeDataSource alloc] init];
QuadCurveMenu *menu = [[QuadCurveMenu alloc] initWithFrame:self.view.bounds dataSource:dataSource];
[self.view addSubview:menu];
}
@end
设置一个代理对象,这通常是显示 QuadCurveMenu 的视图控制器,该控制器通常符合 QuadCurveMenuDelegate
协议。
@interface AwesomeViewController : UIViewController <QuadCurveMenuDelegate>
@end
@implementation AwesomeViewController
- (void)viewDidLoad {
[super viewDidLoad]
AwesomeDataSource *dataSource = [[AwesomeDataSource alloc] init];
QuadCurveMenu *menu = [[QuadCurveMenu alloc] initWithFrame:self.view.bounds dataSource:dataSource];
menu.delegate = self;
[self.view addSubview:menu];
}
- (void)quadCurveMenu:(QuadCurveMenu *)menu didTapMenu:(QuadCurveMenuItem *)mainMenuItem {
NSLog(@"Menu - Tapped");
}
- (void)quadCurveMenu:(QuadCurveMenu *)menu didLongPressMenu:(QuadCurveMenuItem *)mainMenuItem {
NSLog(@"Menu - Long Pressed");
}
- (void)quadCurveMenu:(QuadCurveMenu *)menu didTapMenuItem:(QuadCurveMenuItem *)menuItem {
NSLog(@"Menu Item (%@) - Tapped",menuItem.dataObject);
}
- (void)quadCurveMenu:(QuadCurveMenu *)menu didLongPressMenuItem:(QuadCurveMenuItem *)menuItem {
NSLog(@"Menu Item (%@) - Long Pressed",menuItem.dataObject);
}
- (void)quadCurveMenuWillExpand:(QuadCurveMenu *)menu {
NSLog(@"Menu - Will Expand");
}
- (void)quadCurveMenuDidExpand:(QuadCurveMenu *)menu {
NSLog(@"Menu - Did Expand");
}
- (void)quadCurveMenuWillClose:(QuadCurveMenu *)menu {
NSLog(@"Menu - Will Close");
}
- (void)quadCurveMenuDidClose:(QuadCurveMenu *)menu {
NSLog(@"Menu - Did Close");
}
- (BOOL)quadCurveMenuShouldClose:(QuadCurveMenu *)menu {
// Returning YES will allow the menu to close; NO to prevent it from closing.
return YES;
}
- (BOOL)quadCurveMenuShouldExpand:(QuadCurveMenu *)menu {
// Returning YES will allow the menu to expand; NO to prevent it from expanding.
return YES;
}
@end
您可以配置中心、主菜单项和从主菜单出现的菜单项的外观。
默认情况下,QuadCurveMenu 对主菜单使用
[QuadCurveDefaultMenuItemFactory defaultMainMenuItemFactory]
,对每个菜单项使用[QuadCurveDefaultMenuItemFactory defaultMenuItemFactory]
。这些定义看起来像路径应用程序。
您可以定义自定义的 QuadCurveDefaultMenuItemFactory
实例。
@implementation AwesomeViewController
- (void)viewDidLoad {
[super viewDidLoad]
AwesomeDataSource *dataSource = [[AwesomeDataSource alloc] init];
QuadCurveMenu *menu = [[QuadCurveMenu alloc] initWithFrame:self.view.bounds dataSource:dataSource];
menu.delegate = self;
// Use a facebook center button for the menu
[menu setMainMenuItemFactory:[[QuadCurveDefaultMenuItemFactory alloc] initWithImage:[UIImage imageNamed:@"facebook.png"] highlightImage:[UIImage imageNamed:nil]]];
// Use an unknown user button for the menu items
[menu setMenuItemFactory:[[QuadCurveDefaultMenuItemFactory alloc] initWithImage:[UIImage imageNamed:@"unknown-user.png"] highlightImage:[UIImage imageNamed:nil]]];
[self.view addSubview:menu];
}
您还可以定义符合协议 QuadCurveMenuItemFactory
的自定义对象。
#pragma mark - QuadCurveMenuItemFactory Adherence
- (QuadCurveMenuItem *)createMenuItemWithDataObject:(id)dataObject {
QuadCurveMenuItem *item = [[QuadCurveMenuItem alloc] initWithImage:image
highlightedImage:highlightImage
contentImage:contentImage
highlightedContentImage:highlightContentImage];
[item setDataObject:dataObject];
return item;
}
默认情况下,QuadCurveMenu 以 360 度辐射菜单的形式显示。这可以通过配置现有的菜单目录或定义自定义的 QuadCurveMotionDirector
来进行自定义。
这与原始源中定义的一组菜单属性(控制布局)有所不同。
您可以使用以下选项定义自定义的辐射目录:
rotateAngle
- 菜单的初始起始角度(默认:0 度)menuWholeAngle
- 菜单项显示的可用的总角度(默认:360 度)
endRadius
- 从主菜单中心到(菜单项将坐落的地方)的最终距离
nearRadius
- 菜单项离主菜单中心最近的距离farRadius
- 菜单项离主菜单中心最远的距离您可以使用以下选项定义自定义的线性目录:
angle
- 显示菜单项的角度padding
- 每个菜单项之间的空间如果辐射或线性布局不够强大,您可以定义符合 QuadCurveMotionDirector
接口的自定义目录。
@protocol QuadCurveMotionDirector <NSObject>
- (void)positionMenuItem:(QuadCurveMenuItem *)item
atIndex:(int)index
ofCount:(int)count
fromMenu:(QuadCurveMenuItem *)mainMenuItem;
@end
有几个动画可以通过属性进行自定义。查看示例项目,您应该会看到一个包含应用程序中使用的默认动画的 动画 组。您可以在那里自定义它们,或者定义自己的并设置为 QuadCurveMenu
的属性。
以下是一个交换默认的 选中 和 未选中 动画示例
menu.selectedAnimation = [[QuadCurveShrinkAnimation alloc] init]
menu.unselectedanimation = [[QuadCurveBlowupAnimation alloc] init]
动画是一个遵循协议 QuadCurveAnimation
的对象。
- (NSString *)animationName {
return @"blowup";
}
- (CAAnimationGroup *)animationForItem:(QuadCurveMenuItem *)item {
CGPoint point = item.center;
CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
positionAnimation.values = [NSArray arrayWithObjects:[NSValue valueWithCGPoint:point], 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;
return animationgroup;
}
名称用作在图层中动画的名称。动画本身用 QuadCurveMenuItem
调用,并且应该返回将执行的动作组。