前言
今天有一个小需求,就是在UITextView里面长按显示菜单那里面去自定义菜单,不用系统默认显示的。本来一个很好实现的小功能,网上一查有很多。但是我按照人家给的思路去做了之后发现,新增的自定义菜单是有了,但是系统的还是没有去掉。结果傻眼了。然后摸索了一阵子,突发奇想的就换了个思路搞好了。现在想一下,确实自己很二了。
正文
API分析
显示菜单说白了就是一个VC,用于显示咱们这种长按特殊需求的小界面。
进入UIMenuController的API你会发现这是一个单例类,至于怎么发现的,看下构造方法就知道了:
+ (UIMenuController *)sharedMenuController;
就这么一个构造方法,而且你想一下,菜单显示这个确实是单例实现的最佳范例呀,不可能同时在一个Windows出现。
UIMenuController里面的内容很少,基本都能看懂。不懂得百度一下也就知道,我也不多说了。
UIMenuController只是一个外表显示,一个VC构建了一个空的界面,里面有什么就需要你自己去填充了,当然不可能阿猫阿狗都能填充,这时候就需要UIMenuItem了。
UIMenuItem的API就只有一个方法
NS_CLASS_AVAILABLE_IOS(3_2) __TVOS_PROHIBITED @interface UIMenuItem : NSObject
- (instancetype)initWithTitle:(NSString *)title action:(SEL)action NS_DESIGNATED_INITIALIZER;
@property(nonatomic,copy) NSString *title;
@property(nonatomic) SEL action;
@end
熟悉不,和手势的创建很像吧(本来想说和UITabBarItem很像,但是仔细一想形式很像,作用很像,但是创建方法他们两个有些不合适)。
这个方法就是给一个标题一个事件,没了。灰常简单有木有。
第一次实践进行
然后我就按照我搜索的网上的各位人士给的方法去干:
- (void)viewDidLoad {
[super viewDidLoad];
//设置输入视图
self.textView = [[UITextView alloc]initWithFrame:CGRectMake(10, 20, CGRectGetWidth(self.view.frame) - 20, CGRectGetHeight(self.view.frame) - 40)];
self.textView.layer.borderWidth = 2;
self.textView.layer.borderColor = [UIColor redColor].CGColor;
self.textView.delegate = self;
[self.view addSubview:self.textView];
//设置菜单
UIMenuItem *menuItem = [[UIMenuItem alloc]initWithTitle:@"响应菜单" action:@selector(selfMenu:)];
UIMenuController *menuController = [UIMenuController sharedMenuController];
[menuController setMenuItems:[NSArray arrayWithObject:menuItem]];
}
然后,使用一个UIResponder类特意声明去处理的一个方法,响应者类可以实现这个方法,以根据当前的上下文显示或移除编辑菜单上的命令。(摘抄过来的,我感觉说的挺容易理解的)。
//隐藏系统菜单的方法
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
//允许显示
if (action == @selector(selfMenu:)) {
return YES;
}
//其他不允许显示
return NO;
}
理论上,码上这些,应该是可以隐藏系统的菜单显示自定义的菜单了,然后我去运行:
这是怎么了?fuck the world。不是应该是只显示自定义的菜单了吗,系统的不是应该在UIResponder那个方法里面隐藏了吗?刚开始我有点怀疑我搜到的答案不对,结果又搜了好几个都是这样。然后自己鼓捣一会,结果还是好的,世界总是美好的。
正确做法
继承UITextView,把实现自定义菜单代码放在里面
#import "MyTextView.h"
@implementation MyTextView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
UIMenuItem *menuItem = [[UIMenuItem alloc]initWithTitle:@"响应事件" action:@selector(selfMenu:)];
UIMenuController *menuController = [UIMenuController sharedMenuController];
[
menuController
setMenuItems:[NSArray arrayWithObject:menuItem]];
[menuController setMenuVisible:NO];
}
return self;
}
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(selfMenu:)) {
return YES;
}
return NO;
}
//自定义的事件
- (void)selfMenu:(id)sender{
}
@end
然后,使用自定义的UITextView
- (void)viewDidLoad {
[super viewDidLoad];
//设置输入视图
self.textView = [[MyTextView alloc]initWithFrame:CGRectMake(10, 20, CGRectGetWidth(self.view.frame) - 20, CGRectGetHeight(self.view.frame) - 40)];
self.textView.layer.borderWidth = 2;
self.textView.layer.borderColor = [UIColor redColor].CGColor;
self.textView.delegate = self;
[self.view addSubview:self.textView];
}
运行:
正常运行有木有,我感觉出问题的原因应该是和那个UIResponder的方法有问题,因为我在界面上进行的一切手势事件他都会拦截的。所以直接在UITextView可能造成问题,只是个人猜测,大神知道了请告诉小弟呀。
结语
这也是一个小坑吧。估计会有人像我一样遇到,所以写在这,如果在遇到这个问题的时候看到我这篇小文章,希望对你有帮助。