2018.3.23
iOS中UITextField、UITextView等长按屏幕弹出选择复制黏贴等选项,
UIMenuController即是用来制作我们平时对文本长按屏幕后显示出的复制粘贴等选项菜单的
使用方式之一
1.创建UITextField,UITextView分类/子类,凡继承于UIResponder的类,能调出菜单组件的UI组件都可以进行类似处理;
重写方法- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
2.另需注意的是,在UITableView中有协议方法:(也很简单,顾名思义,类似处理就行)
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender
/**
禁用菜单组件UIMenuController
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
UIMenuController *menuController = [UIMenuController sharedMenuController];
if (menuController) {
menuController.menuVisible = NO;
}
return NO;
}
/**
禁用菜单组件UIMenuController中的某个选项
系统选项,除了下面方法中有的,其它还有(替换,简繁转换,插入绘画,查询,添加,朗读,暂停,共享,添加为模板等..),但暂时还不清楚具体方法
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action==@selector(cut:) || //剪切
action==@selector(copy:) || //复制
action==@selector(paste:) || //黏贴
action==@selector(select:) || //选择
action==@selector(selectAll:) || //多选
action==@selector(delete:) || //删除
action==@selector(makeTextWritingDirectionLeftToRight:) || //使文字写作方向从左到右(图标显示)
action==@selector(makeTextWritingDirectionRightToLeft:) || //使文字写作方向从右到左(图标显示)
action==@selector(toggleBoldface:) || //文字加粗
action==@selector(toggleItalics:) || //文字斜体
action==@selector(toggleUnderline:) || //添加下划线
action==@selector(increaseSize:) || //字体变大
action==@selector(decreaseSize:)) { //字体变小
return NO;
}
return [super canPerformAction:action withSender:sender];
}
/**
结合类似(的更多条件来启用相关选项
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if(action==@selector(copy:)) {
if (!self.selectedTextRange.empty) {
return YES;
} else {
return NO;
}
}
return YES;
}
/**
(重命名/自定义)菜单组件UIMenuController的(选项名称/选项),以下方法仅示例了最常用的四种选项
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
UIMenuController *menuController = [UIMenuController sharedMenuController];
UIMenuItem *selectAllItem = [[UIMenuItem alloc] initWithTitle:@"selectAll" action:@selector(selectAllX:)];
UIMenuItem *selectItem = [[UIMenuItem alloc] initWithTitle:@"select" action:@selector(selectX:)];
UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:@"copy" action:@selector(copyX:)];
UIMenuItem *pasteItem = [[UIMenuItem alloc] initWithTitle:@"paste" action:@selector(pasteX:)];
menuController.menuItems = @[selectItem, selectAllItem, copyItem, pasteItem];
return (action == @selector(selectX:)) ||
(action == @selector(selectAllX:)) ||
(action==@selector(copyX:)) ||
(action==@selector(pasteX:));
}
- (void)selectX:(id)sender {
[self select:sender];
}
- (void)selectAllX:(id)sender {
[self selectAll:sender];
}
- (void)copyX:(id)sender {
[self copy:sender];
}
- (void)pasteX:(id)sender {
[self paste:sender];
}
使用方式之二
子类化UILabel等类似控件,实现相关方法,示例等可以参考下方链接
👇
//是否可以成为第一相应
-(BOOL)canBecomeFirstResponder
//是否可以接收某些菜单的某些交互操作
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
实现了上面的两个方法,使用如下的代码可以唤出UIMenuController控件:[self becomeFirstResponder];
//设置菜单显示的位置 frame设置其文职 inView设置其所在的视图
[[UIMenuController sharedMenuController] setTargetRect:frame inView:self.view];
//将菜单控件设置为可见
[UIMenuController sharedMenuController].menuVisible = YES;
在执行了上面的代码后,系统第一次调用canperformAction:withSender:方法会进行是否显示菜单栏的检测,
如果返回为NO,则不能显示菜单栏,如果返回为YES,之后系统会多次调用canPerformAction:withSender:方法,
用于检测当前Responder对象是否实现了菜单栏上某个选项的触发方法,如果实现了,菜单栏上面的相应按钮会显示,否则不会显示
参考链接:
1.UITextView长按弹出UIMenuController问题
未选择内容之前,不显示剪切等操作,能看出来 [super canPerformAction:action withSender:sender] 是 apple 给我们优化的,因为没有全部选择之前 进行"剪切""拷贝"是没有任何意义的.
注: 你们或许已经发现了, 添加自定义菜单项的时候, 仍然需要canPerformAction, 在这里, 与tableView代理里面的同名方法有什么关系? 是的, 两个都要写, tableView里面的只会影响标准菜单, 文档说只支持这两个UIResponderStandardEditActions (copy/paste)
注: 然而, - (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender这个方法却有点别扭, 一来不需要去实现了, 二来又不能注释掉(你们自己试一下), 等于一定要留一个空的方法体在那里…
注意点总结,要正常显示菜单,必须做到以下几点:
1. -(BOOL)canBecomeFirstResponder 必须返回YES
2. -(BOOL)canPerformAction:(SEL)action withSender:(id)sender 该函数中,要显示的菜单项(包括系统的菜单项)的方法必须返回YES
3. 在显示菜单前,必须调用:[self becomeFirstResponder] 成为第一个响应者
4. 为了马上可以正常显示第二个菜单,必须使用:[menuController setMenuVisible:NO]; 先关闭一下,不然就显示不出来!
PS.文中使用方式之二以及参考链接部分,为了方便起见,多段内容是直接复制参考链接中原文的,如果原作者有疑议,请私我,谢谢。
网友评论