Функции UITextView
Копировать, Вырезать, Выбрать, Выбрать все отображаются по умолчанию, когда я нажимаю на экран. Но в моем проекте UITextField
это только для чтения. Мне эта функция не нужна. Подскажите пожалуйста, как отключить эту функцию.
Функции UITextView
Копировать, Вырезать, Выбрать, Выбрать все отображаются по умолчанию, когда я нажимаю на экран. Но в моем проекте UITextField
это только для чтения. Мне эта функция не нужна. Подскажите пожалуйста, как отключить эту функцию.
Ответы:
Самый простой способ отключить операции монтажного стола - создать подкласс, UITextView
который переопределяет canPerformAction:withSender:
метод, возвращаемый NO
для действий, которые вы не хотите разрешать:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (action == @selector(paste:))
return NO;
return [super canPerformAction:action withSender:sender];
}
Также см. UIResponder
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return NO; }
- чтобы заблокировать все варианты
Подкласс UITextView и перезапись canBecomeFirstResponder:
- (BOOL)canBecomeFirstResponder {
return NO;
}
Обратите внимание, что это применимо только к нередактируемым UITextViews! Не тестировал на редактируемых ...
return NO;
по - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
методу является лучшим вариантом.
Если вы хотите отключить вырезание / копирование / вставку во всем UITextView
своем приложении, вы можете использовать категорию с:
@implementation UITextView (DisableCopyPaste)
- (BOOL)canBecomeFirstResponder
{
return NO;
}
@end
Сохраняет подкласс ... :-)
UITextView
объекту вести себя должным образом, когда, например, он доступен для редактирования и получает прикосновение. Это многое, что нужно преодолеть canPerformAction:withSender:
; вот для чего нужен протокол.
Для меня это было лучшее рабочее решение:
UIView *overlay = [[UIView alloc] init];
[overlay setFrame:CGRectMake(0, 0, myTextView.contentSize.width, myTextView.contentSize.height)];
[myTextView addSubview:overlay];
[overlay release];
Ответ @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 не требуется, то самое простое решение, не использующее подклассы, - просто отключить взаимодействие с пользователем для текстового представления:
textField.userInteractionEnabled = NO;
Самый простой способ - создать подкласс UITextView, который переопределяет canPerformAction: 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;
}
Когда я возвращаю NO в canPerformAction на iOS 7, я получаю много таких ошибок:
<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
, установите для него ДА.Сделав это, вы сможете нажать UITextField
и отобразить варианты выбора UIPickerView
, в это время вы UITextField
действительно не будете реагировать на какое-либо событие касания (это включает касание и удерживание для вырезания, копирования и вставки). Однако вам нужно будет не забыть установить его обратно на ДА, когда вы закрываете свой, UIPickerView
однако вы не сможете получить доступ к своему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
}
Я предоставил рабочий ответ здесь , чтобы отключить выделение текста + лупу, хранение позволило clikable ссылки Надежды , что помогает:
После довольно долгих попыток мне удалось остановить выделение текста, увеличение и сохранение данных (ссылки доступны для кликов и т. Д.), Переопределив addGestureRecognizer в подклассе UITextView, позволяя только 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
я очень легко отключил возможность вырезать, копировать, выбирать и т. Д.
Я поместил 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;
}
}
}
и это сработало для меня. Спасибо.
Swift
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)")
}
Этот метод полностью отключит меню Select, Select All, Paste. Если вы по-прежнему получаете какое-то другое действие, просто добавьте его в условие 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];
}
Вы можете просто создать такую категорию:
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
-object, чтобы решить, нужно ли добавлять действие или нет.
(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)}
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)
}
UITextView имеет два свойства, которые будут делать то, что вам нужно: isSelectable и isEditable. .
Если для 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 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