在附加到 inputAccessoryView 的 UIMenuController 中隐藏“select”、“selectAll”、“paste”?

Posted

技术标签:

【中文标题】在附加到 inputAccessoryView 的 UIMenuController 中隐藏“select”、“selectAll”、“paste”?【英文标题】:Hiding 'select', 'selectAll', 'paste' in a UIMenuController displayed attached to a inputAccessoryView? 【发布时间】:2013-11-15 13:05:23 【问题描述】:

我正在开发一个支持在 UITextView 中编辑属性文本的应用程序。为了向用户提供格式化输入的工具,我使用 inputAccessoryView 来增加键盘的选项,如项目符号列表、编号列表、缩进、缩进、字体控件(粗体、下划线、增加字体大小、减小字体大小)等. 这对于 inputAccessoryView 来说太多了,所以我希望使用 UIMenuController 来提供一种机制,为用户提供更多空间来表达他们的意图。

所以,我有一个带有“listAccessory”按钮的 inputAccessoryView。当它被按下时,我想显示一个带有四个选项(项目符号、数字、增加缩进、减少缩进)的 UIMenuController。但是当我显示这个菜单时,它还包括“选择”、“全选”和“粘贴”。

我的视图中没有定义任何这些方法(如 UIResponderStandardEditActions 非正式协议中定义的 select:、selectAll: 或 paste:)。我已经定义了 canPerformAction:withSender: 并且只对我的选择器回复“YES”。

- (BOOL) canPerformAction:(SEL)selector withSender:(id) sender

    DDLogInfo(@"canPerformAction: %@", NSStringFromSelector(selector));

    if (selector == @selector(formatAsBulletList:)) return YES;
    if (selector == @selector(formatAsNumberedList:)) return YES;
    if (selector == @selector(formatIncreaseIndent:)) return YES;
    if (selector == @selector(formatDecreaseIndent:)) return YES;

    return NO; // return [super canPerformAction:selector withSender:sender];

当我记录在此代码中调用的选择器时,我没有看到任何对“select:”、“selectAll:”或“paste:”的请求,因此我相信 UIMenuController 代码正在测试这些方法对类直接调用 canPerformSelector()。

由于我没有在我的 viewController(派生自 UITableViewController)中实现这些功能,我只能相信 UIMenuController 正在查找响应者链并看到最初启动键盘的响应者是 UITextView,它确实支持全选、全选、粘贴。

所以我有几个问题:

1) 我对情况的理解正确吗?

2) 如何强制不显示这些菜单项?我可以在不关闭键盘的情况下以某种方式暂时中断响应者链吗?

【问题讨论】:

【参考方案1】:

很酷的问题。正如您所理解的那样,问题是。UITextView 是您尝试调用菜单时的第一响应者,因此它会使用 SelectSelect All 操作填充菜单

一种解决方案是继承UITextView 并添加一个额外的属性,允许您短暂阻止项目。

我试过这个,它可以在 UITextField 上运行,因为它是我必须提供的,但没有理由相信它不会在 UITextView 上运行

轻轻地对视图进行子类化。

@interface CharlieDevTextView : UITextView

@property BOOL blockActionMenu;

@end

还有

@implementation CharlieDevTextView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 

    if (self.blockActionMenu) 
        return NO;
    
    return [super canPerformAction:action withSender:sender];



@end

然后当你构建你的菜单时(假设你有一个文本视图的 IBOutlet)

-(void)yellowMellow:(id)sender 




-(void)createMenuForButton:(UIButton *)sender

    UIMenuItem *newInstanceItem = [[UIMenuItem alloc] initWithTitle:@"Woot" action:@selector(yellowMellow:)];

    [UIMenuController sharedMenuController].menuItems = @[newInstanceItem];

    CGPoint apoint = sender.center;

    self.charlieTextView.blockActionMenu = YES;

    [[UIMenuController sharedMenuController] setTargetRect:CGRectMake(apoint.x,apoint.y, 0, 0) inView:sender.superview];

    [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES];

    self.charlieTextView.blockActionMenu = NO;

交替收听 UIMenuControllerWillShowMenuNotificationUIMenuControllerDidHideMenuNotification 以打开和关闭阻塞。

并可能使它稍微不那么难看,创建一个委托而不是一个属性。您的视图控制器将作为代表和判断它是要显示菜单还是注意到菜单已被关闭。

效果基本相同,图案不同。

@protocol CharlieTextViewMenuDelegate <NSObject>

-(BOOL)shouldBlockMenu;

@end

@interface CharlieTextView : UITextView

@property (nonatomic,weak) id< CharlieTextViewMenuDelegate> menuDelegate;

@end

@implementation CharlieDevTextView

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender 

    if ([self.menuDelegate shouldBlockMenu]) 
        return NO;
    
    return [super canPerformAction:action withSender:sender];



@end

【讨论】:

以上是关于在附加到 inputAccessoryView 的 UIMenuController 中隐藏“select”、“selectAll”、“paste”?的主要内容,如果未能解决你的问题,请参考以下文章

视图设置为 inputAccessoryView 在添加回普通视图时抛出异常

IOS 使用输入附件视图切换预测文本视图

优雅地将 UIView 移动到键盘的 inputAccessoryView

如何使用 Swift 在 CustomCell 中实现 inputAccessoryView 到 UITextField?

当用户点击 InputAccessoryView 时如何滚动到 CollectionView 的底部

如何将 UICollectionView 添加到 inputAccessoryView