现在很多App,类似于新浪博客、QQ空间等都支持按住文字,然后弹出一个菜单让你可以选择复制、粘帖等功能。如下图所示
我们都知道这是通过UIMenuController来实现的,而文字的显示一般是通过UILabel来实现的,但是默认情况下UILabel并不支持UIMenuController。不过我们可以给它添加这么一个功能,下面看看具体如何做的。
UIMenuController须知
- 默认情况下, 有以下控件已经支持UIMenuController
- UITextField
- UITextView
- UIWebView
如果想让UILabel也支持上图所示的UIMenuController,就必须做如下操作:
- 自定义UILabel
- 重写2个方法
- 自定义menuitem
新建一个项目,然后再新建两个类,继承自UILabel,实现自定义UILabel支持 UIMenuController
具体实现代码如下:
WSLabel.m
==============
#import "WSLabel.h"
@implementation WSLabel
- (void)awakeFromNib
{
[self setup];
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setup];
}
return self;
}
/**
* 让label可以响应用户操作
*/
- (void)setup
{
self.userInteractionEnabled = YES;
}
//PS:下面两个方法必须在自定义Label里面实现
/**
* 让label有资格成为第一响应者
*/
- (BOOL)canBecomeFirstResponder
{
return YES;
}
/**
* label能执行哪些操作(比如copy, paste等等)
* @return YES:支持这种操作
* 由于这里需要实现自定义的中文菜单,而不是使用默认的,所以这里选择NO
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return NO;
}
@end
在Main.storyboard上面放一个UIlabel,然后拖到viewcontroller里面。
ViewController.m
=====================
//注意这里选择的是自定义的WSLabel,而不是系统的UILabel
@property (weak, nonatomic) IBOutlet WSLabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//给label添加手势,点击触发labelClick方法
[self.label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelClick)]];
}
- (void)labelClick
{
// 1.label要成为第一响应者(作用是:告诉UIMenuController支持哪些操作, 这些操作如何处理)
[self.label becomeFirstResponder];
// 2.显示MenuController
UIMenuController *menu = [UIMenuController sharedMenuController];
/*
添加自定义的MenuItem
注意:
不要写系统自带的copy,paste,delete,不然会生成相应的菜单
*/
UIMenuItem *ding = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copys:)];
UIMenuItem *replay = [[UIMenuItem alloc] initWithTitle:@"粘帖" action:@selector(pastes:)];
UIMenuItem *report = [[UIMenuItem alloc] initWithTitle:@"删除" action:@selector(deletes:)];
menu.menuItems = @[ding, replay, report];
/*
targetRect: MenuController的小箭头需要指向位置
inView: targetRect会以inView后面的控件所在位置(这里是label所在位置)的左上角为自己的坐标原点
上面两个综合起来就确定了菜单所在位置
先用inView,确定坐标原点,再用targetRect相对该坐标原点进行偏移即可以得到菜单所在位置,下面我会具体演示
*/
[menu setTargetRect:self.label.bounds inView:self.label];
[menu setMenuVisible:YES animated:YES];
}
//如果是自定义menuitem,那么该Menuitem对应的方法就必须放在label所在的控制器去实现,而不是自身
- (void)deletes:(UIMenuController *)menu
{
// 清空文字
self.label.text = nil;
}
- (void)copys:(UIMenuController *)menu
{
// 将自己的文字复制到粘贴板
UIPasteboard *board = [UIPasteboard generalPasteboard];
board.string = self.label.text;
}
- (void)pastes:(UIMenuController *)menu
{
// 将粘贴板的文字 复制 到自己身上
UIPasteboard *board = [UIPasteboard generalPasteboard];
self.label.text = board.string;
}@end
最后实现功能如下:
下面我们再看看代码[menu setTargetRect:
inView:]
的作用
情况一:[menu setTargetRect:CGRectMake(100, 100, 0, 0) inView:self.label]
此时菜单的坐标原点是基于label自身
情况二:[menu setTargetRect:CGRectMake(100, 100, 0, 0) inView:self.view]
此时菜单的坐标原点是基于屏幕左上角
大家对比两种情况就知道,这个方法就是调整菜单的位置的。
总结
让UILabel支持自定义的菜单大体分为如下五步:
1、自定义UILabel
2、重写2个方法
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return NO;
}
3、 让label成为第一响应者[self.label
becomeFirstResponder]
4、 显示UIMenuControllersetTargetRect:
inView:
5、 添加自定义的菜单选项
6、 实现各种自定义菜单选项对应的操作方法(删除,赋值,粘贴等)