上海恩美路演iOS技术中心iOS小狮子

UITextView自定义菜单选项(刚刚爬出坑来)

2016-09-22  本文已影响806人  沉默学飞翔

前言

今天有一个小需求,就是在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可能造成问题,只是个人猜测,大神知道了请告诉小弟呀。

结语

这也是一个小坑吧。估计会有人像我一样遇到,所以写在这,如果在遇到这个问题的时候看到我这篇小文章,希望对你有帮助。

备注:本文是自己写的一些理解,可能有不对之处。如有请您能指出来,我马上去校队修改。

上一篇下一篇

猜你喜欢

热点阅读