爲UILabel添加彈出UIMenuController功能


現在很多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:]的作用


此時菜單的座標原點是基於label自身


此時菜單的座標原點是基於屏幕左上角

大家對比兩種情況就知道,這個方法就是調整菜單的位置的。


總結

讓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、 實現各種自定義菜單選項對應的操作方法(刪除,賦值,粘貼等)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章