前言
UIMenuController
是一種UIKit
中提供的一種使用比較簡(jiǎn)單的菜單控件愿吹。今天無意中看到這個(gè)控件驾凶,發(fā)現(xiàn)對(duì)其使用有些模糊了马昨,故此把以前項(xiàng)目中對(duì)它的使用抽出來,做一個(gè)簡(jiǎn)單的總結(jié)
,旨在指導(dǎo)快速上手虽界。
須知
- 默認(rèn)情況下只有
UITextField汽烦、UITextView、UIWebView
支持并內(nèi)置UIMenuController
的控件 - 要讓其他控件也支持UIMenuController(比如UILabel莉御、UIView等)撇吞,就必須自定義控件,并實(shí)現(xiàn)2個(gè)方法特定方法
控件使用效果如下
圖1. 原生UITextField效果
圖2. UILabel自定義樣式
1. 如何讓
UITextField礁叔、UITextView牍颈、UIWebView
顯示UIMenuController
的控件
// 成為第一響應(yīng)者
[self.label becomeFirstResponder];
UIMenuController *menuController = [UIMenuController sharedMenuController];
// 設(shè)置UIMenuItem
menuController.menuItems = menuItems;
// 設(shè)置顯示方向
menuController.arrowDirection = UIMenuControllerArrowUp;
// targetRect: MenuController需要指向的矩形框
// targetView: targetRect會(huì)以targetView的左上角為坐標(biāo)原點(diǎn)
[menuController setTargetRect:self.label.bounds inView:self.label];
// 顯示
[menuController setMenuVisible:YES animated:YES];
2.
自定義
可以使用UIMenuController
的控件(以UILabel為例
)
- 自定義一個(gè)叫
TLMenuLabel
的Label(這步不是重點(diǎn),可以直接跳過
)
- 自定義一個(gè)叫
typedef void(^TLMenuItemDidClick)(NSString *title,UIMenuController *menu);
@interface TLMenuLabel : UILabel
// 對(duì)外API
/** 允許復(fù)制:默認(rèn)YES */
@property (nonatomic,assign) BOOL allowCopy;
/** Ping:默認(rèn)NO */
@property (nonatomic,assign) BOOL allowPing;
/** tracert:默認(rèn)NO */
@property (nonatomic,assign) BOOL allowTracert;
/** tcping:默認(rèn)NO */
@property (nonatomic,assign) BOOL allowTcping;
/** ipconfig:默認(rèn)NO */
@property (nonatomic,assign) BOOL allowDig;
/** 生成報(bào)告:默認(rèn)NO */
@property (nonatomic,assign) BOOL allowReport;
/** 自定義的MenuItem被點(diǎn)擊回調(diào) */
@property (nonatomic,copy) TLMenuItemDidClick itemDidClick;
@end
@implementation TLMenuLabel
// 初始化
- (void)awakeFromNib {
[super awakeFromNib];
[self setup];
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setup];
}
return self;
}
- (void)setup {
self.userInteractionEnabled = YES;
_allowCopy = YES;
_allowPing = YES;
_allowTracert = NO;
_allowTcping = YES;
_allowDig = NO;
_allowReport = YES;
UILongPressGestureRecognizer *longPress
= [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:@selector(onLongPress:)];
[self addGestureRecognizer:longPress];
}
@end
- 重寫2個(gè)特定方法(
重點(diǎn)
),重寫后這個(gè)自定義label就支持UIMenuController控件了
- 重寫2個(gè)特定方法(
// 1. 重寫 `- canBecomeFirstResponder`
// ??不能是` - (BOOL)becomeFirstResponder`
- (BOOL)canBecomeFirstResponder{
return self.allowCopy || self.allowPing ||
self.allowTracert || self.allowTcping ||
self.allowDig || _allowReport;
}
// 2. 重寫`- canPerformAction: withSender:`
/**
* label能執(zhí)行哪些操作(比如copy, paste等等)
* @return YES:支持這種操作
*/
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
// 根據(jù)你的需求 使能 你需要的操作琅关,這個(gè)方法會(huì)根據(jù)你設(shè)置的menuItems多次調(diào)用
if (action == @selector(copyText:)){
return self.allowCopy;
}
if (action == @selector(ping:)){
return self.allowPing;
}
if (action == @selector(tracert:)){
return self.allowTracert;
}
if (action == @selector(tcping:)){
return self.allowTcping;
}
if (action == @selector(dig:)){
return self.allowDig;
}
if (action == @selector(report:)){
return self.allowReport;
}
return NO; // 禁止系統(tǒng)操作類型(返回YES颂砸,系統(tǒng)操作類型也會(huì)顯示)
}
- 顯示(此處通過長(zhǎng)按手勢(shì)喚醒)
- (void)onLongPress:(UILongPressGestureRecognizer *)longPress{
switch (longPress.state) {
case UIGestureRecognizerStateBegan:
{
_bgColor = self.backgroundColor;
self.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9];
// 需要顯示的額外條件
if (self.text == nil || self.text.length < 1) return;
if (![self canBecomeFirstResponder]) return;
[self becomeFirstResponder];
// 創(chuàng)建UIMenuItem
NSArray *titles = @[@"Ping",@"Tracert",@"Tcping",@"Dig",@"生成報(bào)告",@"復(fù)制"];
NSArray *actions = @[@"ping:",@"tracert:",@"tcping:",@"dig:",@"report:",@"copyText:"];
self.items = [NSMutableArray array];
for (NSString *title in titles) {
NSUInteger index = [titles indexOfObject:title];
// ??要確保這些Action都有實(shí)現(xiàn)(見下面第4步)
SEL sel = NSSelectorFromString(actions[index]);
UIMenuItem *newItem = [[UIMenuItem alloc] initWithTitle:title action:sel];
[self.items addObject:newItem];
}
// 獲取UIMenuController單例
UIMenuController *controller = [UIMenuController sharedMenuController];
controller.menuItems = self.items;
[controller setTargetRect:self.bounds inView:self];
[controller setMenuVisible:YES animated:YES];
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed:
self.backgroundColor = _bgColor;
break;
default:
break;
}
}
- UIMenuItem對(duì)應(yīng)Action的實(shí)現(xiàn)(
此步主要是提醒要實(shí)現(xiàn)Action
)
- UIMenuItem對(duì)應(yīng)Action的實(shí)現(xiàn)(
- (void)ping:(UIMenuController *)menu
{
if (self.itemDidClick) {
self.itemDidClick(@"ping", menu);
}
}
- (void)tracert:(UIMenuController *)menu
{
if (self.itemDidClick) {
self.itemDidClick(@"tracert -d", menu);
}
}
- (void)tcping:(UIMenuController *)menu
{
if (self.itemDidClick) {
self.itemDidClick(@"tcping", menu);
}
}
- (void)dig:(UIMenuController *)menu
{
if (self.itemDidClick) {
self.itemDidClick(@"dig", menu);
}
}
- (void)report:(UIMenuController *)menu {
if (self.itemDidClick) {
self.itemDidClick(@"report", menu);
}
}
- (void)copyText:(UIMenuController *)menu
{
// 將自己的文字復(fù)制到粘貼板
UIPasteboard *board = [UIPasteboard generalPasteboard];
board.string = self.text;
// if (self.itemDidClick) {
// self.itemDidClick(@"copy", menu);
// }
}