uimenucontroller的使用
2. Menu所处的View必须实现 – (BOOL)canPerformAction:withSender, 并根据需求返回YES或NO
3. 使Menu所处的View成为First Responder (becomeFirstResponder)
4. 定位Menu (- setTargetRect:inView:)
5. 展示Menu (- setMenuVisible:animated:)
UIMenuController *popMenu = [UIMenuController sharedMenuController];
UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:@”1″action:@selector(menuItem1Pressed:)];
UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:@”2″action:@selector(menuItem2Pressed:)];
UIMenuItem *item3 = [[UIMenuItem alloc] initWithTitle:@”3″action:@selector(menuItem3Pressed:)];
UIMenuItem *item4 = [[UIMenuItem alloc] initWithTitle:@”4″action:@selector(menuItem4Pressed:)];
NSArray *menuItems = [NSArray arrayWithObjects:item1,item2,item3,item4,nil];
[popMenu setMenuItems:menuItems];
[popMenu setArrowDirection:UIMenuControllerArrowDow
[item4 release];
[item3 release];
[item2 release];
[item1 release];
[popMenu setTargetRect:CGRectMake(162,195,0,0) inView:self.dialView];
[popMenu setMenuVisible:YES animated:YES];
后来在StackOverFlow上看到这个问题,同时也在cocoachina上找到相应的方法,原来要想显示弹出菜单,必须实现3个方法,缺一不可:
- becomFirstResponder方法,使view或者viewController的self成为第一响应者,可以在相应文件的任意地方调用实现该方法,不过建议与UIMenuController放在一起。
[self becomeFirstResponder];
- 设置-(BOOL) canBecomeFirstResponder的返回值为YES,原因不言而喻。
-(BOOL) canBecomeFirstResponder{
return YES;
}
- 重载函数-(BOOL) canPerfomAction:(SEL)action withSender:(id)sender,设置要显示的菜单项,返回值为YES。若不进行任何限制,则将显示系统自带的所有菜单项(很多的,自己可以 试一下),在此,只显示自定义的4项,即:
-(BOOL) canPerformAction:(SEL)action withSender:(id)sender{
if (action == @selector(menuItem1Pressed:) || action ==@selector(menuItem2Pressed:) ||
action == @selector(menuItem3Pressed:) || action ==@selector(menuItem4Pressed:)) {
return YES;
}
return NO; //隐藏系统默认的菜单项
}
至于相应的菜单响应通过各selector函数来实现,如:
- (IBAction) menuItem1Pressed:(id)sender{
txtInputLabel.text = @”1″;
[[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES];
}
如果将系统默认的菜单也显示出来,那么自定义的菜单将作为第二菜单,调用菜单时默认显示的是第一菜单,如果要直接显示第二菜单,根据cocoachina上一位同行总结出来的经验,先设置菜单可见性为NO即可:
[popMenu setMenuVisible:NO animated:YES];
UIMenuItem* miCustom1 = [[[UIMenuItem alloc] initWithTitle: @"MENU1"action:@selector( onCustom1: )] autorelease];UIMenuItem* miCustom2 = [[[UIMenuItem alloc] initWithTitle: @"MENU2"action:@selector( onCustom2: )] autorelease]; UIMenuController* mc = [UIMenuController sharedMenuController]; mc.menuItems = [NSArray arrayWithObjects: miCustom1, miCustom2,nil];
- 附加在菜单的视图的 canBecomeFirstResponser 必须返回 YES,这意味着必须子类化。例如最常用的显示元素 UITableViewCell 和 UILabel 默认返回的是 NO
UILongPressGestureRecognizer
直到 iOS 3.2 才提供, which means that the long press to initiate the menu display had to be implemented viatouchesBegan:withEvent:
,touchesMoved:withEvent:
, andtouchesEnded:withEvent:
. Every custom long press recognizer might use a different delay constant, which could easily confuse users who are used to another app's implementation.
而最新的 iOS 使用两种基本方法解决了这个问题,一个是表格单元格,另外一个是定制菜单选项。
指定情景: UITableViewCell on iOS 5
如果你只是想在 UITableViewCell 中使用系统提供的复制粘贴功能(大部分情况是这样),iOS 5.0 有更简单的方法:
01 | - ( BOOL )tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath { |
02 | return YES; |
03 | } |
04 |
05 | - ( BOOL )tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { |
06 | if (action == @selector(copy:)) { |
07 | return YES; |
08 | } |
09 | |
10 | return NO; |
11 | } |
12 |
13 | - ( void )tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { |
14 | if (action == @selector(copy:)) { |
15 | [UIPasteboard generalPasteboard].string = [data objectAtIndex:indexPath.row]; |
16 | } |
17 | } |
该菜单调用 tableView:canPerformAction:forRowAtIndexPath:withSender
以确认是否该显示系统菜单选项并调用 tableView:performAction:forRowAtIndexPath:withSender:
当用户选择某个选项时.
定制菜单项
如果你想使用定制菜单项,下面代码比较隐晦,但非常灵活。你需要检测是否用户长按并显示菜单,而最简单的方法就是在表格单元格中使用 UILongPressGestureRecognizer
1 | UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; |
2 | [cell addGestureRecognizer:recognizer]; |
为了让菜单显示,目标视图必须在 responder 链中,很多 UIKit 视图默认并无法成为一个 responder ,因此你需要之类这些视图重载 canBecomeFirstResponder 方法范围 YES
在下面例子中,我们使用定制类 TSTableViewCell 并实现了长按选择器
01 | - ( void )longPress:(UILongPressGestureRecognizer *)recognizer { |
02 | if (recognizer.state == UIGestureRecognizerStateBegan) { |
03 | TSTableViewCell *cell = (TSTableViewCell *)recognizer.view; |
04 | [cell becomeFirstResponder]; |
05 | |
06 | UIMenuItem *flag = [[UIMenuItem alloc] initWithTitle:@ "Flag" action:@selector(flag:)]; |
07 | UIMenuItem *approve = [[UIMenuItem alloc] initWithTitle:@ "Approve" action:@selector(approve:)]; |
08 | UIMenuItem *deny = [[UIMenuItem alloc] initWithTitle:@ "Deny" action:@selector(deny:)]; |
09 |
10 | UIMenuController *menu = [UIMenuController sharedMenuController]; |
11 | [menu setMenuItems:[NSArray arrayWithObjects:flag, approve, deny, nil]]; |
12 | [menu setTargetRect:cell.frame inView:cell.superview]; |
13 | [menu setMenuVisible:YES animated:YES]; |
14 | } |
15 | } |
16 |
17 | - ( void )flag:(id)sender { |
18 | NSLog(@ "Cell was flagged" ); |
19 | } |
20 |
21 | - ( void )approve:(id)sender { |
22 | NSLog(@ "Cell was approved" ); |
23 | } |
24 |
25 | - ( void )deny:(id)sender { |
26 | NSLog(@ "Cell was denied" ); |
27 | } |
There is only one small gotcha with UIMenuItem
: if the specified action is not implemented by your view controller, that item will not appear in the menu.