当UITextView
我在屏幕上按下时,默认情况下会显示 的复制、剪切、选择、全选功能。但是,在我的项目中,UITextField
它是只读的。我不需要这个功能。请告诉我如何禁用此功能。
31 回答
禁用粘贴板操作的最简单方法是创建一个子类,UITextView
该子类覆盖为您不想允许的操作canPerformAction:withSender:
返回的方法:NO
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(paste:))
return NO;
return [super canPerformAction:action withSender:sender];
}
继承 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];
如果您想在所有 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;
}
When I return NO in the canPerformAction on iOS 7 I will get a lot of errors like this:
<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.
My solution is the following:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
}];
return [super canPerformAction:action withSender:sender];
}
The trick is to hide the menu controller in the next cycle on the main queue (just after it is displayed).
这是在 UITextView 中禁用整个选择/复制/粘贴菜单的最简单方法
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
[UIMenuController sharedMenuController].menuVisible = NO;
return NO;
}
如果您想禁用弹出窗口,请UITextField
尝试使用此UITextFieldDelegate
方法切换isUserInteractionEnabled
。
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = false
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
textField.isUserInteractionEnabled = true
return true
}
如果您想用一个替换键盘,比如说,UIPicker
作为inputView
(当然工具栏作为一个inputAccesotyView
),那么这个解决方法可能会有所帮助......
- 实施
textFieldShouldBeginEditing:
- 内放
textField.userInteractionEnabled = NO;
- 然后,当您要关闭 时
UIPickerView
,将其设置为 YES。
通过这样做,您可以点击UITextField
并显示可供选择的选项UIPickerView
,此时您UITextField
实际上不会对任何触摸事件做出反应(这包括用于剪切、复制和粘贴的触摸并按住)。但是,您必须记住在关闭时将其设置回 YES,UIPickerView
但是您将无法UIPickerView
再次访问您的。
它失败的唯一时刻是当用户开始点击并按住 时UITextView
,您会第一次看到剪切复制和粘贴。这就是为什么您应该始终验证您的输入的原因。这是我能想到的最简单的。另一种选择是使用UILabel
只读文本,但你错过了很多很棒的功能UITextView
。
从 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;
}
我已经做了。在我UITextView
的身上,我很容易禁用了剪切、复制、选择等选项。
我将 a 放置UIView
在放置 , 的同一位置UITextView
,但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
}
如果您想向 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
}
}
迅速
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
和覆盖- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
是禁用不需要的操作的另一种可能性。
使用gestureRecognizer
-object 的类来决定是否应该添加操作。
您可以像这样创建类别:
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
请查找示例代码以供参考:
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
}
斯威夫特 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 有两个属性可以满足您的需求:isSelectable和isEditable。
将 isEditable 设置为 false 将避免用户编辑文本,将isSelectable设置为 false 将避免用户在 textView 中选择文本,因此这将阻止显示操作菜单。
(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)}
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 添加类新类