Как отключить редактирование UITextField, но по-прежнему принимать касание?

107

Составляю UITextFieldчто есть UIPickerViewкак inputView. Все хорошо, за исключением того, что я могу редактировать, копируя, вставляя, вырезая и выделяя текст, а мне это не нужно. Только средство выбора должно изменять текстовое поле.

Я узнал , что я могу отключить редактирование путем установки setEnabledили setUserInteractionEnabledк NO. Хорошо, но TextField перестает реагировать на прикосновения, и средство выбора не появляется.

Что я могу сделать для этого?

Луис де Пра
источник

Ответы:

131

Используя делегат текстового поля, есть метод

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

Верните NO, и любая попытка пользователя отредактировать текст будет отклонена.

Таким образом, вы можете оставить поле включенным, но при этом запретить людям вставлять в него текст.

Ник Локвуд
источник
4
Если вы по-прежнему хотите реагировать на прикосновение, реагируйте на прикосновение, а не на прикосновение внутрь. В противном случае ваше мероприятие никогда не будет вызвано.
radven
@NickLockwood есть ли какие-либо способы, позволяющие текстовому полю стать первым респондентом, но отключить взаимодействие с пользователем и скрыть курсор?
onmyway133
1
@entropy Я предполагаю, что вы хотите иметь возможность выбирать контент, чтобы пользователь мог его скопировать? Если вы создаете подкласс UITextField, вы можете переопределить практически любое поведение - например, вы можете заставить поле всегда выбирать все, когда пользователь прикасается к нему, что эффективно скрывает курсор.
Ник Локвуд,
1
@LoryLory это то же самое, просто используйте вместо этого синтаксис Swift для метода делегата.
Ник Локвуд,
5
Точнее, при необходимости мы можем использовать textFieldShouldBeginEditing
Навин Шан
22

Переведите ответ Ника на быстрый:

P / S: Return false => текстовые поля не могут вводиться, редактировать с клавиатуры. Он просто может установить текст по коду. EX: textField.text = "Моя строка здесь"

override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return false
}
Ли
источник
3
У меня это не работает. Просто нажмите и удерживайте текстовое поле, пока не появится увеличение и появится меню вырезания / копирования / вставки iOS, и я смогу использовать его для изменения текста.
RowanPD
2
swift 4: `func textField (_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replaceString string: String) -> Bool {return false}`
lionello
16

Это было бы проще всего:

in viewDidLoad: (установите делегата только для текстовых полей, которые нельзя редактировать.

self.textfield.delegate=self;

и вставьте эту функцию делегата:

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
return NO;
}

Это оно!

Анкиш Джайн
источник
27
Это препятствует отображению сборщика и не решает описанную проблему
Мартин Локетт
6
@MartinLockett Если вы запускаете UIPickerViewповедение из этого метода делегата, оно работает хорошо.
Альберт Бори
9

В быстром 3+:

class MyViewController: UIViewController, UITextFieldDelegate {

   override func viewDidLoad() {
      self.myTextField.delegate     = self
   }

   func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
      if textField == myTextField {
         // code which you want to execute when the user touch myTextField
      }
      return false
   }
}
Надиша Лакмал
источник
7

Было бы более элегантно создать собственный подкласс, UITextFieldкоторый возвращает NOдля всех вызовов canPerformAction:withSender:(или, по крайней мере, где actionесть @selector(cut)или @selector(paste)), как описано здесь .

Кроме того, я бы также реализовал строку - (BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range replaceString: (NSString *) в соответствии с предложением Ника, чтобы отключить ввод текста с клавиатуры Bluetooth.

MrMage
источник
Не могу придумать, как это сделать. Подклассы canPerformActionи shouldChangeCharactersInRangeметоды никогда не вызываются.
Нестор
7

Просто поместите UIButton точно по всему UITextField без текста метки, который сделает его «невидимым». Эта кнопка может принимать и делегировать касания вместо текстового поля, при этом содержимое текстового поля все еще отображается.

Тимм Кент
источник
7

В Swift:

func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
    questionField.resignFirstResponder();
    // Additional code here
    return false
}
Саранья
источник
3

Я использовал решение, предоставленное MrMage. Единственное, что я бы добавил, это то, что вы должны отказаться от UITextView как первого респондента, иначе вы застрянете с выделенным текстом.

Вот мой быстрый код:

class TouchableTextView : UITextView {

    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        self.resignFirstResponder()
        return false
    }

    override func shouldChangeTextInRange(range: UITextRange, replacementText text: String) -> Bool {
        self.resignFirstResponder()
        return false
    }

}
Leedrick
источник
1

В качестве альтернативы, которая обрабатывает UIPickerView и листы действий, проверьте ActionSheetPicker

https://github.com/TimCinel/ActionSheetPicker

Включены коконады. Он обрабатывает все кнопки отмены и завершения на листе действий. Примеры в образце проекта великолепны. Я выбираю ActionSheetStringPicker, который легко обрабатывает только параметры на основе String, но API может обрабатывать почти все, что я могу придумать.

Первоначально я начал решение, очень похожее на отмеченный галочкой ответ, но наткнулся на этот проект, и мне потребовалось примерно 20 минут, чтобы интегрировать в свое приложение все, включая использование кокоподов: ActionSheetPicker (~> 0.0)

Надеюсь это поможет.

Загрузите проект git и посмотрите следующие классы:

  • ActionSheetPickerViewController.m
  • ActionSheetPickerCustomPickerDelegate.h

Вот примерно большая часть кода, который я добавил, плюс импорт * .h.

- (IBAction)gymTouched:(id)sender {
      NSLog(@"gym touched");

      [ActionSheetStringPicker showPickerWithTitle:@"Select a Gym" rows:self.locations initialSelection:self.selectedIndex target:self successAction:@selector(gymWasSelected:element:) cancelAction:@selector(actionPickerCancelled:) origin:sender];
 }


- (void)actionPickerCancelled:(id)sender {
    NSLog(@"Delegate has been informed that ActionSheetPicker was cancelled");
}


- (void)gymWasSelected:(NSNumber *)selectedIndex element:(id)element {
    self.selectedIndex = [selectedIndex intValue];

    //may have originated from textField or barButtonItem, use an IBOutlet instead of element
    self.txtGym.text = [self.locations objectAtIndex:self.selectedIndex];
}


-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    return NO;  // Hide both keyboard and blinking cursor.
}
Ник Н
источник
Обновленная версия модуля находится здесь. github.com/skywinder/ActionSheetPicker-3.0
Nick N
1

Чтобы предотвратить редактирование UITextField при использовании UIPickerView для выбора значений (в Swift):

self.txtTransDate = self.makeTextField(self.transDate, placeHolder: "Specify Date")
self.txtTransDate?.addTarget(self, action: "txtTransDateEditing:", forControlEvents: UIControlEvents.EditingDidBegin)

func makeTextField(text: String?, placeHolder: String) -> UITextField {
    var textField = UITextField(frame: CGRect(x: 140, y: 0, width: 220.00, height: 40.00));
    textField.placeholder = placeHolder
    textField.text = text
    textField.borderStyle = UITextBorderStyle.Line
    textField.secureTextEntry = false;
    textField.delegate = self
    return textField
}


func txtTransDateEditing(sender: UITextField) {
    var datePickerView:UIDatePicker = UIDatePicker()
    datePickerView.datePickerMode = UIDatePickerMode.Date
    sender.inputView = datePickerView
    datePickerView.addTarget(self, action: Selector("datePickerValueChanged:"), forControlEvents: UIControlEvents.ValueChanged)
}

func datePickerValueChanged(sender: UIDatePicker) {
    var dateformatter = NSDateFormatter()
    dateformatter.dateStyle = NSDateFormatterStyle.MediumStyle
    self.txtTransDate!.text = dateformatter.stringFromDate(sender.date)
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool  {
    self.resignFirstResponder()
    return false
}
Тиру
источник
0

Этот обходной путь работает. Поместите прозрачный UIView над текстовым полем и реализуйте следующий код:

- (void)viewDidLoad
{
 [super viewDidLoad];

   UILongPressGestureRecognizer *press = [[UILongPressGestureRecognizer alloc]             initWithTarget:self action:@selector(longPress)];
[transparentView addGestureRecognizer:press];
 [press release];
  press = nil;
}

-(void)longPress
{
   txtField.userInteractionEnabled = NO;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   txtField.userInteractionEnabled = YES;
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
  [txtField becomeFirstResponder];
}
Cocoakomali
источник
1
Меня смущает, почему вы не используете простой прозрачный UIButton + touchUpInside, а вместо этого выбрали жест UIView +.
Чен Ли Йонг
0

Сделайте ваш inputView представленным скрытым текстовым полем, которое также изменяет текст представленного и отключенного.

Сандро Веццали
источник
0

Не совсем уверен, насколько это круто, но единственное, что помогло в моем случае, - это добавление целевого действия и вызов endEditing. Поскольку мое средство выбора контролирует мое значение UITextField.text, я могу закрыть клавиатуру, как только пользователь щелкнет поле. Вот код:

uiTextFieldVariable.addTarget(self, action: #selector(dismissKeyboard), for: .editingDidBegin)

@objc private func dismissKeyboard() {
    endEditing(true)
}
Бруно Мирра
источник
-5

Я использовал :

[self.textField setEnabled:NO];

и его работа отлично

Крис
источник
-7

Это сработало для меня [textview setEditable:NO]; . Вышеупомянутые ответы слишком усложняют ситуацию.

Толгаб
источник
1
OP написал: «Я узнал, что могу отключить редактирование, установив для setEnabled или setUserInteractionEnabled: NO значение NO. Хорошо, но TextField перестает реагировать на прикосновения, и средство выбора не отображается». Ваш ответ остановит все события, исход которых нежелателен.
Maninvan
@Tolgab не является даже связанным решением для этого OP!
Анураг Шарма