UIMenuController的用法

在很多应用当中, 当我们长按一段文字或者图片的时候会弹出一个菜单,我们通过这个菜单可以实现文字的复制、剪切、删除和各种操作:这个菜单就是UIMenuController,系统默认支持UITextField、UITextView、UIWebView控件的UIMenuController操作;对于系统不支持的UIMenuController操作的控件,我们就要自定义控件的UIMenuController来实现相关功能。

一. UIMenuController相关方法

创建一个UIMenuController对象

#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) UIMenuController *sharedMenuController;
#else
+ (UIMenuController *)sharedMenuController;
#endif

class语义属于类属性, 与swift的类属性相对应

显示或隐藏菜单

/**
 *  设置menu显示的位置信息
 *
 *  @param targetRect menu需要显示的矩形区域
 *  @param targetView targetRect会以targetView的左上角为坐标原点进行显示
 */
- (void)setTargetRect:(CGRect)targetRect inView:(UIView *)targetView;

// 菜单相对于矩形的位置
@property(nonatomic) UIMenuControllerArrowDirection arrowDirection NS_AVAILABLE_IOS(3_2); // default is UIMenuControllerArrowDefault

 注意 
1. targetRect一旦设定以后,矩形范围不会跟随view的移动而移动,如果view移动,必须相应的更新targetRect 。比如tableView 点击cell出现menu,当按住对应的cell,拖动tableView滚动时,menu不会随着对应的cell一起滚动 
2. targetRect通常设置为需要弹出menu控件的bounds,targetView设置为对应的控件本身

 更新menu的显示与对应的方法

- (void)update;

自定义menuItem

@property(nullable, nonatomic,copy) NSArray<UIMenuItem *> *menuItems NS_AVAILABLE_IOS(3_2); // default is nil. these are in addition to the standard items


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

编辑菜单箭头指向view的位置

默认取决于view在界面的位置

typedef NS_ENUM(NSInteger, UIMenuControllerArrowDirection) {
    UIMenuControllerArrowDefault, // up or down based on screen location
    UIMenuControllerArrowUp NS_ENUM_AVAILABLE_IOS(3_2),
    UIMenuControllerArrowDown NS_ENUM_AVAILABLE_IOS(3_2),
    UIMenuControllerArrowLeft NS_ENUM_AVAILABLE_IOS(3_2),
    UIMenuControllerArrowRight NS_ENUM_AVAILABLE_IOS(3_2),
}

menu支持的通知

UIMenuControllerWillShowMenuNotification;
UIMenuControllerDidShowMenuNotification;
UIMenuControllerWillHideMenuNotification;
UIMenuControllerDidHideMenuNotification;
UIMenuControllerMenuFrameDidChangeNotification;

二. 自定义控件的UIMenuController

两个重要方法(如果自定义的menu显示效果存在问题,一般是这两个方法出现了问题)

//设置控件可以成为第一响应者,注意不是每个控件都可以成为第一响应者
- (BOOL)canBecomeFirstResponder;    // default is NO
/**
 *  设置控件能够执行那些具体操作
 *  @param action 具体操作
 *  @return YES:支持该操作
 */
- (BOOL)canPerformAction:(SEL)action withSender:(nullable id)sender;
// Allows an action to be forwarded to another target. By default checks -canPerformAction:withSender: to either return self, or go up the responder chain.

一般步骤

1. 设置控件成为第一响应者 2. 创建UIMenuController 3. 创建UIMenuItem(如果需要自定义item) 4. 在对应控件上重写上述两个方法

 UIMenuController按钮点击常见系统方法

- (void)cut:(nullable id)sender NS_AVAILABLE_IOS(3_0);
- (void)copy:(nullable id)sender NS_AVAILABLE_IOS(3_0);
- (void)paste:(nullable id)sender NS_AVAILABLE_IOS(3_0);
- (void)select:(nullable id)sender NS_AVAILABLE_IOS(3_0);
- (void)selectAll:(nullable id)sender NS_AVAILABLE_IOS(3_0);
- (void)delete:(nullable id)sender NS_AVAILABLE_IOS(3_2);
- (void)makeTextWritingDirectionLeftToRight:(nullable id)sender NS_AVAILABLE_IOS(5_0);
- (void)makeTextWritingDirectionRightToLeft:(nullable id)sender NS_AVAILABLE_IOS(5_0);

//私有方法
   _promptForReplace:
   _transliterateChinese:
   _showTextStyleOptions:
   _define:
   _addShortcut:
   _accessibilitySpeak:
   _accessibilitySpeakLanguageSelection:
   _accessibilityPauseSpeaking:
   _share:

自定义label的UIMenuController

#import "CopyLabel.h"

@implementation CopyLabel

// 当nib文件被加载的时候
- (void)awakeFromNib {

    [super awakeFromNib];

}

// 当nib文件对象被实例化的时候
- (instancetype)initWithCoder:(NSCoder *)aDecoder {

    if (self = [super initWithCoder:aDecoder]) {
         [self setUpViews];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {
        [self setUpViews];
    }
    return self;
}

- (void)setUpViews {

    self.userInteractionEnabled = YES;
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)];
    [self addGestureRecognizer:longPress];
}

- (void)longPressAction:(UILongPressGestureRecognizer *)sender {

    // 1. 设置label为第一响应者
    [self becomeFirstResponder];
    // 2. 设置UIMenuController
    UIMenuController *menu = [UIMenuController sharedMenuController];

    // 当长按label的时候,这个方法会被不断调用, menu就会出现一闪一闪不断显示,需要在此处进行判断
    if (menu.isMenuVisible) {
        return;
    }

    // 自定义UIMenuController
    UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:@"剪切" action:@selector(myCut:)];
    UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:@"粘贴" action:@selector(myPaste:)];
    menu.menuItems = @[item1, item2];
    [menu setTargetRect:self.bounds inView:self];
    [menu setMenuVisible:YES animated:YES];
}

#pragma mark - 对控件权限进行设置
/** 
    设置label可以成为第一响应者
    注意:不是每个控件都有资格成为第一响应者
 */
- (BOOL)canBecomeFirstResponder {

    return YES;
}

/** 
    label能够执行哪些具体操作
    @param action 具体操作
    @return YES:支持该操作
 */
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {

    if (action == @selector(myCut:) || action == @selector(myPaste:)) {
        return YES;
    }
    return NO;
}

- (void)myCut:(UIMenuController *)menu {

    [self copy:menu];
    self.text = nil;

}

- (void)myPaste:(UIMenuController *)menu {

    UIPasteboard *paste = [UIPasteboard generalPasteboard];
    if (paste.string) {
        self.text = paste.string;
    }

}

- (void)copy:(UIMenuController *)menu {

    // 当没有文字的时候调用这个方法会崩溃
    if (!self.text) {
        return;
    }
    // 复制文字到剪切板
    UIPasteboard *paste = [UIPasteboard generalPasteboard];
    paste.string = self.text;
}

@end

自定义button的UIMenutroller

#import "SharedButton.h"

@implementation SharedButton

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

- (instancetype)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {
        [self addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];

    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {

    if (self = [super initWithCoder:aDecoder]) {
        [self addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
    }
    return self;
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (void)buttonAction:(UIButton *)sender {

    [self becomeFirstResponder];
    UIMenuController *menu = [UIMenuController sharedMenuController];

    UIMenuItem *item0 = [[UIMenuItem alloc] initWithTitle:@"分享" action:@selector(sharedAction:)];
    UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:@"评论" action:@selector(commentsAction:)];
    UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:@"点赞" action:@selector(praiseAction:)];
    menu.menuItems = @[item0, item1, item2];
    menu.arrowDirection = UIMenuControllerArrowRight;
    [menu setTargetRect:self.bounds inView:self];
    [menu setMenuVisible:YES animated:YES];
}

- (void)sharedAction:(UIMenuController *)menu {
    NSLog(@"分享");
}

- (void)commentsAction:(UIMenuController *)menu {
    NSLog(@"评论");
}

- (void)praiseAction:(UIMenuController *)menu {

    NSLog(@"点赞");
}

UITableViewCell的UIMenuController

1.在TableViewCell里实现方法:

- (BOOL)canBecomeFirstResponder {
    return YES;
}

2.在controller里实现方法

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    UIMenuController *menu = [UIMenuController sharedMenuController];
    if (menu.isMenuVisible) {
        [menu setMenuVisible:NO animated:YES];
    } else {
        TableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
        self.selectedCell = cell;

        [cell becomeFirstResponder];

        UIMenuItem *item0 = [[UIMenuItem alloc] initWithTitle:@"分享" action:@selector(shareAction:)];
        UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:@"评论" action:@selector(commentsAction:)];
        UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:@"点赞" action:@selector(praiseAction:)];
        menu.menuItems = @[item0, item1, item2];
        [menu setTargetRect:CGRectMake(0, cell.frame.size.height * 0.5, cell.frame.size.width, cell.frame.size.height) inView:cell.contentView];
        [menu setMenuVisible:YES animated:YES];

    }    
}

- (void)shareAction:(UIMenuController *)menu {

    NSLog(@"分享%@", self.selectedCell.nameLabel.text);
}

- (void)commentsAction:(UIMenuController *)menu {

    NSLog(@"评论%@", self.selectedCell.nameLabel.text);
}

- (void)praiseAction:(UIMenuController *)menu {

    NSLog(@"点赞%@", self.selectedCell.nameLabel.text);
}

 

转载于:https://my.oschina.net/u/2616184/blog/1554664

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值