第一次使用UIMenuController,遇见一些问题,记录如下。
概念
UIMenuController即菜单控制器,是一个单例对象,用来复制,粘贴,删除等内容的操作。
使用步骤
通过下面三部完成UIMenuController的使用,缺一不可:
- 通过[UIMenuController sharedMenuController]来获取实例对象;
- 通过
- (void)setTargetRect:(CGRect)targetRect inView:(UIView *)targetView
设置菜单的显示位置,例如设置targetRect为下图的红色区域,那么菜单会显示在targetRect上方中间位置,如果上方中间位置在屏幕上不能够显示,那么会显示在下方中间位置。如果targetRect的宽度高度设置为零,那么会在一个点显示。(菜单会根据设置的区域自动调整位置,以便能全部显示出来); - 通过
menuVisible
属性设置为YES(或者setMenuVisible:animated:
方法)令菜单显示出来。
使用菜单
假设点击控制器的view显示菜单,那么在控制的touchesBegan方法中按照上面说的三步设置UIMenuController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:CGRectMake(100, 300, 200, 20) inView:self.view];
menu.menuVisible = YES;
}
此时我们运行程序,点击控制的view并没有弹出菜单,原因是:
1.控制器或者UIView能够成为first responder ,需要实现下面方法
- (BOOL)canBecomeFirstResponder
{
return YES;
}
2.在显示菜单时需要设置为first responder ,在touchesBegan中添加[self becomeFirstResponder];
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self becomeFirstResponder]; //设置为第一响应者
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:CGRectMake(100, 300, 200, 20) inView:self.view];
menu.menuVisible = YES;
}
3.并且需要实现UIResponder的canPerformAction:withSender:方法,该方法与编辑菜单相关,与返回YES的方法关联的菜单将显示出来。
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(paste:))
{
return YES;
} else if (action == @selector(cut:))
{
return YES;
}
else{
return NO;
}
}
其中paste:
和cut:
方法都定义在UIResponderStandardEditActions协议,都是与菜单相关的。
由于只有paste:
和cut:
方法能够响应,因此只显示cut和paste两个菜单,显示效果如下
如果直接返回YES,那么所有菜单都会显示,如下图。
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return YES;
}
说明:如果canPerformAction:withSender: 的first responder没有处理事件,会顺着响应链向上抛。
使用自定义菜单
可以通过UIMenuItem来自定义菜单,需要设置菜单的显示内容以及点击菜单的后的处理方法。然后将自定义的UIMenuItem添加到UIMenuController的menuItems(一个数组)属性中。其它使用过程与上面讲解的使用菜单的过程一样。 具体使用见下面例子,
添加自定义菜单
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self becomeFirstResponder]; //成为第一响应者
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:CGRectMake(100, 300, 200, 20) inView:self.view];
// 定义两个菜单a和b
UIMenuItem *a = [[UIMenuItem alloc] initWithTitle:@"a"
action:@selector(aAction)];
UIMenuItem *b = [[UIMenuItem alloc] initWithTitle:@"b"
action:@selector(bAction)];
// 自定义菜单添加到菜单栏中
menu.menuItems = @[like,writeBack,report];
menu.menuVisible = YES;
}
实现aAction
和bAction
方法
- (void)aAction{
NSLog(@"--aAction--")
}
- (void)bAction{
NSLog(@"--bAction--")
}
控制器或者UIView能够成为first responder
- (BOOL)canBecomeFirstResponder
{
return YES;
}
实现canPerformAction:withSender:方法
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
// 显示一个系统的paste以及自定义的a,b菜单
if (action == @selector(paste:) ||
action == @selector(aAction) ||
action == @selector(bAction))
{
return YES;
}
else{
return NO;
}
}
运行程序,显效果如下
说明:系统的菜单会显示在自定义菜单之前。
其它说明
如下图红色箭头所指所示,菜单箭头指针默认向下,可以通过设置arrowDirection
属性改变其方向,支持上下左右四个方法。
箭头指针最下面的点即- (void)setTargetRect:(CGRect)targetRect inView:(UIView *)targetView
方法中targetRect说设置的位置,具体指向的点见使用步骤说解释。