How disable Copy, Cut, Select, Select All in UITextView

当我按下屏幕时,默认显示 UITextView的复制,剪切,选择,选择所有功能。但是,在我的项目中,UITextField只是只读的。我不需要这个功能。请告诉我如何禁用此功能。

105957 次浏览

禁用粘贴板操作的最简单方法是创建一个 UITextView的子类,该子类覆盖 canPerformAction:withSender:方法,为您不希望允许的操作返回 NO:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(paste:))
return NO;
return [super canPerformAction:action withSender:sender];
}

也请参阅 UIResponder

我已经做到了。在我的 UITextView我已经禁用剪切,复制,选择等选项很容易。

我在我放置 UITextView的同一个地方放置了一个 UIView,但是在 self.view上添加了一个 touchDelegate方法,如下所示:

(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *scrollTouch=[touches anyObject];
if(scrollTouch.view.tag==1)
{
NSLog(@"viewTouched");
if(scrollTouch.tapCount==1)
[textView1 becomeFirstResponder];
else if(scrollTouch.tapCount==2)
{
NSLog(@"double touch");
return;
}


}
}

对我很有效,谢谢。

这是在 UITextView 中禁用整个选择/复制/粘贴菜单的最简单方法

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[UIMenuController sharedMenuController].menuVisible = NO;
return NO;
}

最简单的方法是创建一个覆盖 canPerformAction 的 UITextView 子类: withSender:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[UIMenuController sharedMenuController].menuVisible = NO;  //do not display the menu
[self resignFirstResponder];                      //do not allow the user to selected anything
return NO;
}

子类 UITextView 并覆盖 canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
return NO;
}

注意,这只适用于不可编辑的 UITextView。

如果你不需要 UITextView 滚动,那么最简单的不涉及子类的解决方案就是简单地禁用文本视图的用户交互:

textField.userInteractionEnabled = NO;

如果你想禁用剪切/复制/粘贴应用程序的 所有 UITextView,你可以使用 类别:

@implementation UITextView (DisableCopyPaste)


- (BOOL)canBecomeFirstResponder
{
return NO;
}


@end

它保存了一个子类... : -)

这对我来说是最好的解决方案:

UIView *overlay = [[UIView alloc] init];
[overlay setFrame:CGRectMake(0, 0, myTextView.contentSize.width, myTextView.contentSize.height)];
[myTextView addSubview:overlay];
[overlay release];

发信人: https://stackoverflow.com/a/5704584/1293949

这对我很有效。确保你在 textView 上调用 resignFirstResponder

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[self.textView resignFirstResponder];
return NO;
}

自 iOS7以来,UITextView 上有一个属性:

 @property(nonatomic,getter=isSelectable) BOOL selectable;

这样可以避免文本选择,对我来说非常有用。

当我在 iOS7的 canPerformAction 中返回 NO 时,我会得到很多这样的错误:

<Error>: CGContextSetFillColorWithColor: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.

我的解决办法如下:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
}];
return [super canPerformAction:action withSender:sender];
}

诀窍是在主队列的下一个循环中(在它显示之后)隐藏菜单控制器。

You can just create category like this:

UITextView + Selectable.h

@interface UITextView (Selectable)


@property (nonatomic, assign, getter = isTextSelectable) bool textSelectable;


@end

UITextView + Selectable.m

#import "UITextView+Selectable.h"


#import <objc/runtime.h>


#define TEXT_SELECTABLE_PROPERTY_KEY @"textSelectablePropertyKey"


@implementation UITextView (Selectable)


@dynamic textSelectable;


-(void)setTextSelectable:(bool)textSelectable {
objc_setAssociatedObject(self, TEXT_SELECTABLE_PROPERTY_KEY, [NSNumber numberWithBool:textSelectable], OBJC_ASSOCIATION_ASSIGN);
}


-(bool)isTextSelectable {
return [objc_getAssociatedObject(self, TEXT_SELECTABLE_PROPERTY_KEY) boolValue];
}


-(bool)canBecomeFirstResponder {
return [self isTextSelectable];
}


@end

如果您希望将键盘替换为,比方说,UIPicker作为 inputView(当然还有一个工具栏作为 inputAccesotyView) ,那么这个解决方案可能会有所帮助..。

  • 实现 textFieldShouldBeginEditing:
  • 内置 textField.userInteractionEnabled = NO;
  • 然后当你要关闭 UIPickerView的时候,把它设置为 YES。

通过这样做,你将能够点击 UITextField并显示选项从 UIPickerView,在这个时候你的 UITextField将,事实上,不会反应任何触摸事件(这包括触摸和保持剪切,复制和粘贴)。但是,你必须记住设置它回到是当你关闭你的 UIPickerView但是你将不能再次访问你的 UIPickerView

失败的唯一时刻是当用户开始点击并持有 UITextView,然后你会看到剪切复制和粘贴第一次。这就是为什么您应该始终验证您的输入。这是我能想到的最简单的办法了。另一种选择是对只读文本使用 UILabel,但是您错过了 UITextView的许多伟大功能。

Subclassing UITextView and overriding - (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer is another possibility to disable unwanted actions.

使用 gestureRecognizer对象的类来决定是否应该添加操作。

@ rpetrich 的回答对我很有用,我把扩展代码发布出去以免节省时间。

在我的情况下,我不想弹出任何东西,但我确实希望 UITextField 能够成为第一响应者。

不幸的是,当您点击并保持文本字段时,仍然会看到放大镜弹出。

@interface NoSelectTextField : UITextField


@end


@implementation NoSelectTextField


- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if (action == @selector(paste:) ||
action == @selector(cut:) ||
action == @selector(copy:) ||
action == @selector(select:) ||
action == @selector(selectAll:) ||
action == @selector(delete:) ||
action == @selector(makeTextWritingDirectionLeftToRight:) ||
action == @selector(makeTextWritingDirectionRightToLeft:) ||
action == @selector(toggleBoldface:) ||
action == @selector(toggleItalics:) ||
action == @selector(toggleUnderline:)
) {
return NO;
}
return [super canPerformAction:action withSender:sender];
}


@end

Swift 4

class NoSelectTextField: UITextField {


override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(paste(_:)) ||
action == #selector(cut(_:)) ||
action == #selector(copy(_:)) ||
action == #selector(select(_:)) ||
action == #selector(selectAll(_:)) ||
action == #selector(delete(_:)) ||
action == #selector(makeTextWritingDirectionLeftToRight(_:)) ||
action == #selector(makeTextWritingDirectionRightToLeft(_:)) ||
action == #selector(toggleBoldface(_:)) ||
action == #selector(toggleItalics(_:)) ||
action == #selector(toggleUnderline(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}


}

我提供了一个工作答案 给你禁用文本选择 + 放大镜,保持启用可爱的链接 希望这能有所帮助:

经过很长一段时间的尝试,我设法停止文本选择,放大,并保持数据检测(链接可点击等)通过覆盖在 UITextView 子类上的 addGestureIdentiizer 只允许 UILongPressGestureIdentiizer 延迟触摸结束:

UIUnselectableTextView.m

-(void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
if([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] && gestureRecognizer.delaysTouchesEnded)
{
[super addGestureRecognizer:gestureRecognizer];
}
}

这可以在故事板中轻松实现(Xcode 6)。只要在属性检查器中取消选择可编辑和可选择。您仍然可以滚动文本视图。enter image description here

(SWIFT) 如果你只想要一个没有任何菜单选项或放大镜的基本文本字段,那么创建一个返回 false 的 UITextField 子类,返回 estureIdentiizerShouldBegin:

class TextFieldBasic: UITextField {
override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {


return false
}
}

这将绕过文本字段上的所有触摸功能,但仍然允许您使用弹出式键盘来添加/删除字符。

如果你正在使用情节串连板,只需将新创建的类分配给文本字段,或者如果你正在以编程方式创建一个文本字段:

var basicTextField = TextFieldBasic()
basic = basicTextField(frame: CGRectMake(10, 100, 100,35))
basic.backgroundColor = UIColor.redColor()
self.view.addSubview(basic)


basic.becomeFirstResponder()

斯威夫特

textView.selectable = false // disable text selection (and thus copy/paste/etc)

相关资料

textView.editable = false // text cannot be changed but can still be selected and copied
textView.userInteractionEnabled = false // disables all interaction, including scrolling, clicking on links, etc.
override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool
{
NSOperationQueue .mainQueue().addOperationWithBlock({ () -> Void in


[UIMenuController .sharedMenuController() .setMenuVisible(false, animated: true)]


})
return super.canPerformAction(action, withSender: sender)}

你可以在你的故事板中通过取消勾选这些选项来解决这个问题:

enter image description here

或者你可以这样设置:

textView.selectable = false
textView.editable = false

For Swift 3 it's changed to:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}

Swift 3

为了做到这一点,您需要子类化您的 UITextView 并将此方法。

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if (action == #selector(copy(_:))) {
return false
}


if (action == #selector(cut(_:))) {
return false
}


if (action == #selector(paste(_:))) {
return false
}


return super.canPerformAction(action, withSender: sender)
}

Use func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool } in place of textFieldShouldBeginEditing.

class ViewController: UIViewController , UITextFieldDelegate {


@IBOutlet weak var textField: UITextField!


override func viewDidLoad() {
super.viewDidLoad()
//Show date picker
let datePicker = UIDatePicker()
datePicker.datePickerMode = UIDatePickerMode.date
textField.tag = 1
textField.inputView = datePicker
}


func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField.tag == 1 {
textField.text = ""
return false
}


return true
}


func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.tag == 1 {
textField.text = ""
return false
}


return true
}
}

创建一个名为 StopPasteAction.swift 的新类

import UIKit


class StopPasteAction: UITextField {


override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
}

使用当前 TextField 添加新类

enter image description here

如果你想添加一个自定义选项到你的 UITextView,但是禁用现有的功能,这就是你如何在 Swift 3上做到这一点:

要禁用复制、粘贴、剪切功能,请创建一个子类并覆盖以下内容:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}

在 ViewController 上,您可以让 CustomTextView 添加以下选项来添加您的选项:

  let selectText = UIMenuItem(title: "Select", action: #selector(ViewController.selected))


func selected() {


if let selectedRange = textView.selectedTextRange, let
selectedText = textView.text(in: selectedRange) {


}




print("User selected text: \(selectedText)")


}

此方法将完全禁用“选择,全部选择,粘贴”菜单。如果您仍然得到一些其他操作,那么只需将其添加到如果条件中,如下所示。

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender // This is to disable select / copy / select all / paste menu
{
if (action == @selector(copy:) || action == @selector(selectAll:) || action == @selector(select:) || action == @selector(paste:))
return NO;
return [super canPerformAction:action withSender:sender];
}

子类 UITextView-Swift 4.0

     override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}

如果你想为 UITextField禁用弹出窗口,那么试试这个 UITextFieldDelegate方法来切换 isUserInteractionEnabled

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = false
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = true
return true
}

UITextView has two property that will do what you need: 可供选择 and 是可编辑的.

将 isEditable 设置为 false 可以避免用户编辑文本,将 可供选择设置为 false 可以避免用户在 textView 中选择文本,这样可以防止显示操作菜单。

请参考示例代码:

 override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(copy(_:)) || action == #selector(paste(_:)) || action == #selector(UIResponderStandardEditActions.paste(_:)) ||
action == #selector(replace(_:withText:)) ||
action == #selector(UIResponderStandardEditActions.cut(_:)) ||
action == #selector(UIResponderStandardEditActions.select(_:)) ||
action == #selector(UIResponderStandardEditActions.selectAll(_:)) ||
action == #selector(UIResponderStandardEditActions.delete(_:)) ||
action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight(_:)) ||
action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleBoldface(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleItalics(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleUnderline(_:)) ||
action == #selector(UIResponderStandardEditActions.increaseSize(_:)) ||
action == #selector(UIResponderStandardEditActions.decreaseSize(_:))


{
return false
}


return true
}

如果你正在寻找一个 iOS > = 13.0版本,你可以简单地使用这个扩展在任何实现级别,直到 UIResponder:

extension UITextField {
override var editingInteractionConfiguration: UIEditingInteractionConfiguration {
return .none
}
}

You can use method swizzling for acheiving this. Method swizzling is to be performed for the method : func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool

如果你有多个 textFeld/textView 整个应用程序,在不同的情节串连板,如果你想要他们所有放弃剪贴板选项一次,那么这是最好的解决方案。方法 swizzling 实现可以添加到 textFeld/textView 扩展中。Swizzle 函数可以在应用程序委托中调用。