Jak wyłączyć edycję UITextField, ale nadal akceptować dotyk?


107

Robię, UITextFieldże ma UIPickerViewas inputView. Wszystko jest w porządku, poza tym, że mogę edytować przez kopiowanie, wklejanie, wycinanie i zaznaczanie tekstu, a tego nie chcę. Tylko Picker powinien modyfikować pole tekstowe.

Nauczyłem się, że mogę wyłączyć edycji poprzez ustawienie setEnabledlub setUserInteractionEnableddo NO. Ok, ale TextField przestaje reagować na dotyk, a selektor nie pojawia się.

Co mogę zrobić, żeby to osiągnąć?

Odpowiedzi:


131

Korzystając z delegata pola tekstowego, istnieje metoda

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

Zwróć NIE z tego, a każda próba edycji tekstu przez użytkownika zostanie odrzucona.

W ten sposób możesz pozostawić to pole włączone, ale nadal uniemożliwić ludziom wklejanie do niego tekstu.


4
Jeśli nadal chcesz reagować na dotyk, odpowiedz na „dotykanie”, a nie na „dotykanie w środku”. W przeciwnym razie wydarzenie nigdy nie zostanie wywołane.
radven

@NickLockwood Czy są jakieś sposoby, abyśmy mogli nadal zezwolić textField na zostanie pierwszym reagującym, ale wyłączyć interakcję z użytkownikiem i ukryć daszek?
onmyway133

1
@entropy Zakładam, że chcesz mieć możliwość wybrania treści, aby użytkownik mógł ją skopiować? Jeśli utworzysz podklasę UITextField, możesz przesłonić prawie każde zachowanie - np. Możesz zmusić pole, aby zawsze wybierało wszystko, gdy użytkownik dotknie, co skutecznie ukryje kursor.
Nick Lockwood

1
@LoryLory to to samo, zamiast tego użyj składni Swift dla metody delegata.
Nick Lockwood,

5
Dokładniej możemy użyć „textFieldShouldBeginEditing” w razie potrzeby
Naveen Shan

22

Przetłumacz odpowiedź Nicka na szybki:

P / S: Return false => pola tekstowe nie mogą być wprowadzane, edytuj za pomocą klawiatury. Po prostu może ustawić tekst za pomocą kodu.EX: textField.text = "Mój ciąg tutaj"

override func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return false
}

3
To nie działa na mnie. Po prostu kliknij długo pole tekstowe, aż pojawi się powiększenie i pojawi się menu wycinania / kopiowania / wklejania iOS i mogę użyć tego do zmiany tekstu.
RowanPD

2
swift 4: `func textField (_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replaceString string: String) -> Bool {return false}`
lionello

16

To byłoby najprostsze ze wszystkich:

in viewDidLoad: (ustaw delegata tylko dla pól tekstowych, które nie powinny być edytowalne.

self.textfield.delegate=self;

i wstaw tę funkcję delegata:

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

Otóż ​​to!


27
Zapobiega to przedstawianiu selektora, a więc nie rozwiązuje opisanego problemu
Martin Lockett

6
@MartinLockett Jeśli wyzwolisz UIPickerViewzachowanie z tej metody delegata, działa dobrze.
Albert Bori,

9

W Swift 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

Byłoby bardziej eleganckie utworzenie niestandardowej podklasy UITextFieldzwracającej NOwszystkie wywołania do canPerformAction:withSender:(lub przynajmniej gdzie actionjest @selector(cut)lub @selector(paste)), jak opisano tutaj .

Ponadto zaimplementowałbym również ciąg - (BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range replaceString: (NSString *) ciąg zgodnie z sugestią Nicka, aby wyłączyć wprowadzanie tekstu z klawiatur Bluetooth.


Nie mogę za całe życie wymyślić, jak to zrobić. Podklasy canPerformActioni shouldChangeCharactersInRangemetody nigdy nie są wywoływane.
Nestor

7

Po prostu umieść przycisk UIButton dokładnie nad całym UITextField bez tekstu etykiety, co czyni go „niewidocznym”. Ten przycisk może odbierać i delegować dotknięcia zamiast pola tekstowego, a zawartość pola tekstowego jest nadal widoczna.


7

W Swift:

func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
    questionField.resignFirstResponder();
    // Additional code here
    return false
}

3

Skorzystałem z rozwiązania dostarczonego przez MrMage. Jedyne, co chciałbym dodać, to zrezygnować z UITextView jako pierwsza osoba odpowiadająca, w przeciwnym razie utkniesz z zaznaczonym tekstem.

Oto mój szybki kod:

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
    }

}

1

Aby uzyskać alternatywę, która obsługuje UIPickerView i Action Sheets, wyewidencjonuj ActionSheetPicker

https://github.com/TimCinel/ActionSheetPicker

Włączono cocoapods. Obsługuje wszystkie przyciski anulowania i zakończenia na arkuszu akcji. Przykłady w przykładowym projekcie są świetne. Wybieram ActionSheetStringPicker, który z łatwością obsługuje tylko opcje oparte na ciągach, ale API może obsłużyć większość wszystkiego, o czym przyjdzie mi do głowy.

Początkowo uruchomiłem rozwiązanie podobne do odpowiedzi zaznaczonej znacznikiem, ale natknąłem się na ten projekt i zajęło mi około 20 minut, aby zintegrować rzeczy z moją aplikacją w celu użycia, w tym używania kokopodów: ActionSheetPicker (~> 0.0)

Mam nadzieję że to pomoże.

Pobierz projekt git i zapoznaj się z następującymi klasami:

  • ActionSheetPickerViewController.m
  • ActionSheetPickerCustomPickerDelegate.h

Oto z grubsza większość dodanego przeze mnie kodu, plus importy * .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.
}

Zaktualizowana wersja kapsuły jest tutaj. github.com/skywinder/ActionSheetPicker-3.0
Nick N

1

Aby zapobiec edycji UITextField podczas korzystania z UIPickerView do wybierania wartości (w języku 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

To obejście działa. Umieść przezroczysty UIView nad polem tekstowym i zaimplementuj następujący kod:

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

1
Nie wiem, dlaczego nie używasz prostego przezroczystego UIButton + touchUpInside i zamiast tego wybrałeś gest UIView +.
Chen Li Yong

0

Spraw, aby Twój inputView był prezentowany przez ukryte pole tekstowe, które również zmienia tekst prezentowanego i wyłączonego.


0

Nie jestem do końca pewien, jak hacky to jest, ale jedyną rzeczą, która zrobiła sztuczkę w moim przypadku, było dodanie akcji docelowej i wywołanie endEditing. Ponieważ mój selektor kontroluje moją wartość UITextField.text, mogłem zamknąć klawiaturę, gdy tylko użytkownik kliknie pole. Oto kod:

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

@objc private func dismissKeyboard() {
    endEditing(true)
}

-5

Użyłem :

[self.textField setEnabled:NO];

i działa dobrze


-7

To zadziałało dla mnie [textview setEditable:NO]; Powyższe odpowiedzi zbytnio komplikują sytuację.


1
OP napisał: „Dowiedziałem się, że mogę wyłączyć edycję, ustawiając setEnabled lub setUserInteractionEnabled: NO na NO. Ok, ale TextField przestaje reagować na dotykanie, a selektor nie pojawia się”. Twoja odpowiedź zatrzyma wszystkie wydarzenia, których rezultat nie był pożądany.
maninvan

@Tolgab nie jest nawet powiązanym rozwiązaniem dla tego OP!
Anurag Sharma
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.