繁体   English   中英

如何在 UITextView 中禁用 Copy, Cut, Select, Select All

[英]How disable Copy, Cut, Select, Select All in UITextView

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

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

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

另见UIResponder

继承 UITextView 并覆盖 canBecomeFirstResponder:

- (BOOL)canBecomeFirstResponder {
    return NO;
}

请注意,这仅适用于不可编辑的 UITextViews! 还没有在可编辑的上测试它...

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

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

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

@implementation UITextView (DisableCopyPaste)

- (BOOL)canBecomeFirstResponder
{
    return NO;
}

@end

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

@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

斯威夫特 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 滚动,那么不涉及子类化的最简单解决方案是简单地禁用文本视图的用户交互:

textField.userInteractionEnabled = NO;

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

- (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;
}

当我在 iOS 7 上的 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];
}

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

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

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

如果您想用UIPicker作为inputView替换键盘(当然还有一个工具栏作为inputAccesotyView ),那么这种解决方法可能会有所帮助......

  • 实现textFieldShouldBeginEditing:
  • 里面放textField.userInteractionEnabled = NO;
  • 然后,当您即将关闭UIPickerView时,将其设置为 YES。

通过这样做,您可以点击UITextField并显示从UIPickerView中选择的选项,此时您的UITextField确实不会对任何触摸事件做出反应(这包括触摸并按住剪切、复制和粘贴)。 但是,当您关闭UIPickerView时,您必须记住将其设置回 YES,但是您将无法再次访问您的UIPickerView

它失败的唯一时刻是当用户开始点击并按住UITextView时,您会第一次看到剪切复制和粘贴。 这就是为什么您应该始终验证您的输入的原因。 这是我能想到的最简单的。 另一种选择是将UILabel用于只读文本,但您会错过UITextView的许多出色功能。

如果要禁用UITextField的弹出窗口,请尝试使用此UITextFieldDelegate方法来切换isUserInteractionEnabled

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

从 iOS 7 开始,UITextView 上有一个属性:

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

这可以防止视图允许文本选择。 对我很有用。

子类 UITextView - swift 4.0

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

这对我有用。 确保您在 textView 上调用 resignFirstResponder

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

这可以在故事板(Xcode 6)中轻松完成。 只需取消选中 Attributes Inspector 中的 Editable 和 Selectable。 您仍然可以滚动文本视图。 在此处输入图像描述

您可以通过取消选中以下框在情节提要中解决此问题:

在此处输入图像描述

或者您可以像这样以编程方式设置:

textView.selectable = false
textView.editable = false

我已经做了。 在我的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 子类上的 addGestureRecognizer 来停止文本选择、放大和保持数据检测(链接可点击等),只允许 UILongPressGestureRecognizer 延迟触摸结束:

UIUnselectableTextView.m

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

对于Swift 3 ,它改为:

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

迅速

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.

如果您想向 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)")

    }

此方法将完全禁用选择、全选、粘贴菜单。 如果您仍然获得其他操作,则只需将其添加到 if 条件中,如下所示。

- (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];
    }

如果您正在寻找 iOS >=13.0 版本,您可以简单地在任何级别的实现中使用此扩展,直至 UIResponder:

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

您可以像这样创建类别:

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

继承UITextView并覆盖- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer是禁用不需要的操作的另一种可能性。

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

(SWIFT)如果您只想要一个没有菜单选项或放大镜的基本文本字段,则创建一个 UITextField 的子类,返回 false 到 gestureRecognizerShouldBegin:

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()
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)}

斯威夫特 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)
    }

UITextView 有两个属性可以满足您的需求: isSelectableisEditable

将 isEditable 设置为 false 将避免用户编辑文本,将isSelectable设置为 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
    }

您可以使用方法调配来实现这一点。 将为方法执行方法调配:func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool

如果您在整个应用程序中有多个 textFeild/textView,在不同的故事板中,并且如果您希望所有这些都一次性丢弃剪贴板选项,那么这是最好的解决方案。可以在 textFeild/textView 扩展中添加方法调配实现。 Swizzle 函数可以在应用程序委托的didginish 启动中调用。

我解决了文本字段中选择器的问题。 删除选择。 足够的“CGRect.null”

override func caretRect(for position: UITextPosition) -> CGRect {
    return CGRect.null
}
override func selectionRects(for range: UITextRange) -> [UITextSelectionRect] {
    return []
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return false
}

使用func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { retrun bool }代替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 添加类新类

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM