2017-06-22 4 views
0

Ich habe UITableView mit etwa 20 Zeilen, die jeweils eine UITextField enthalten. Wenn ich zum ersten Mal in ein Textfeld klicke, wird die Tastatur geöffnet und ich kann dieses Textfeld bearbeiten. Wenn ich auf das nächste Textfeld klicke (die Tastatur wird ständig angezeigt), wird die Tastatur zwar weiterhin angezeigt, aber der blaue Cursor befindet sich nicht im neuen Textfeld und ich kann keinen Text eingeben. Aber wenn ich wieder auf ein anderes Textfeld tippe, funktioniert es gut. Dieses Verhalten tritt abwechselnd auf, einmal funktioniert es das andere Mal nicht.UITextField in UITableView wird nicht zum Ersthelfer

Die Delegate-Methode textFieldShouldBeginEditing(_:) wird immer aufgerufen, ob ich sie bearbeiten kann oder nicht. Die Delegate-Methode textFieldDidBeginEditing(_:) wird nur beim Bearbeiten aufgerufen.

Dies ist der Code für cellForRowAt

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "TextFieldCell")! 
    let titleLabel = cell.viewWithTag(1) as! UILabel 
    let contentTextField = cell.viewWithTag(2) as! FixableTextField 
    contentTextField.delegate = self 
    contentTextField.inputAccessoryView = doneToolbar 

    // Enable/disable editing for text fields 
    if isEditing { 
     contentTextField.enableEditing() 
    } else { 
     contentTextField.disableEditing() 
    } 

    // Present Profile Data 
    if profileUpdateBuffer != nil { 

     switch indexPath.row { 
     case 0: 
      titleLabel.text = "Count" 
      contentTextField.text = "\(profileUpdateBuffer!.count)" 
      contentTextField.purposeID = "count" 
      contentTextField.keyboardType = .numberPad 

     case 1: 
      titleLabel.text = "City" 
      contentTextField.text = "\(profileUpdateBuffer!.city)" 
      contentTextField.purposeID = "city" 
      contentTextField.keyboardType = .default 

     // ... 

     case 20: 
      titleLabel.text = "Name" 
      contentTextField.text = "\(profileUpdateBuffer!.name)" 
      contentTextField.purposeID = "name" 
      contentTextField.keyboardType = .default 

     default: 
      titleLabel.text = "" 
      contentTextField.text = "" 
     } 

     return cell 
    } 

    // No data available -> show info in first row 
    else { 
     if indexPath.row == 0 { 
      titleLabel.text = "No data" 
      contentTextField.text = "No data" 
     } 
     else { 
      titleLabel.text = "" 
      contentTextField.text = "" 
     } 
     return cell 
    } 
} 

Die enableEditing() und disableEditing() Methode aus der Klasse sind FixableTextField. Ich kann sehen, dass die Textfelder sind immer aktiviert, weil ich das Textfeld Grenze

// Extract from FixableTextField class 
func enableEditing() { 
    self.isEnabled = true 
    self.borderStyle = .roundedRect 
} 

func disableEditing() { 
    self.isEnabled = false 
    self.borderStyle = .none 
} 

-Code für den UITextField

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { 

    // Delete empty field indicator "-" 
    if textField.text == "-" { 
     textField.text = "" 
    } 

    //Move profileTable's contentView to correct position 
    if textField is FixableTextField { 
     let path = IndexPath(row: rowMap[(textField as! FixableTextField).purposeID]!, section: 0) 
     moveContentViewUp(indexPath: path) 
    } 
    return true 
} 



func textFieldDidEndEditing(_ textField: UITextField) { 

    // Save new value to profileUpdateBuffer 
    do { 
     try self.profileUpdateBuffer?.setProperty(value: textField.text!, key: (textField as! FixableTextField).purposeID) 
    } catch ProfileError.PropertySettingWrongType { 
     let falseInputAlert = UIAlertController(title: "False Input", message: "The input for this field is not valid.", preferredStyle: .alert) 
     falseInputAlert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) 
     self.present(falseInputAlert, animated: true, completion: nil) 
    } catch { 
     print("Error when trying to set property for profileUpdateBuffer in ProfileViewController") 
    } 

    // Display new data in table 
    profileTable.reloadData() 
} 

Auszug aus setProperty Methode sehen kann, die von der Klasse ist ProfileData. profileUpdateBuffer ist vom Typ ProfileData

func setProperty(value:String, key:String) throws { 
    switch key { 
    case "count": 
     count = value 

    case "city": 
     count = value 

    // ... 

    case "name": 
     name = value 

    default: 
     throw ProfileError.PropertySettingWrongType 
    } 
} 
+0

Bitte senden Sie Ihren Code, damit wir Ihnen helfen können. Vor allem Ihre CellForRowAt indexPath-Funktion. Wie fügen Sie Listener zu Ihren textFields hinzu? –

+0

Danke, natürlich werde ich. – Codey

+0

Haben Sie eine Filterlogik in 'textFieldShouldBeginEditing (_ :)'? Ich sehe, dass Sie auch Ihren VC als Delegierten aller Ihrer Textfelder haben. Haben Sie eine Logik, um zwischen Zellen in Delegiertenmethodenimplementierungen zu unterscheiden? Sie können versuchen, den TextField-Delegaten in der Zelle zu verschieben, damit jede Zelle für sich selbst verantwortlich ist. – kr45ko

Antwort

1

ich ein kleines Programm gemacht haben, das Verhalten, das Sie beschreiben, zu imitieren. Es ist das Problem scheint durch Tabellenansicht Daten verursacht wird, am Ende Ihrer textFieldDidEndEditing(_:) Nachladen:

func textFieldDidEndEditing(_ textField: UITextField) { 

    // Save new value to profileUpdateBuffer 
    do { 
     try self.profileUpdateBuffer?.setProperty(value: textField.text!, key: (textField as! FixableTextField).purposeID) 
    } catch ProfileError.PropertySettingWrongType { 
     let falseInputAlert = UIAlertController(title: "False Input", message: "The input for this field is not valid.", preferredStyle: .alert) 
     falseInputAlert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) 
     self.present(falseInputAlert, animated: true, completion: nil) 
    } catch { 
     print("Error when trying to set property for profileUpdateBuffer in ProfileViewController") 
    } 

    // Display new data in table 
    profileTable.reloadData() 
} 

Versuchen profileTable.reloadData() im Interesse des Experiments zu entfernen, die Ursache des Problems zu bestätigen (ja, deine andere Zellen nicht bleibe auf dem Laufenden).

Eine Möglichkeit, dies zu lösen, ist die Verwendung von direkten Zellenaktualisierungen unter visibleCells in textFieldDidEndEditing(_:). Ich sehe profileUpdateBuffer? ist Ihr Datenmodell. Aktualisieren Sie einfach die titleLabel- und textField-Eigenschaften Ihrer Zelle manuell aus Ihrem Modell, wenn sie sich in der Eigenschaft visible cells der Tabellenansicht befinden.

Wenn Sie die Zellen entsprechend der Größe möchten, verwenden Sie Autolayout und UITableViewAutomaticDimension für Tischhöhe Ansicht Reihe mit beginUpdates()/endUpdates() Anrufe kombiniert.

Für weitere Details, wie man direkte Zellmanipulation und/oder dynamische Zellgrößenaktualisierung erreicht, ohne den Tastaturfokus zu verlieren check the accepted answer on this question Ich habe bereits geantwortet.

Hoffe, das wird helfen!

+0

Vielen Dank für Ihre ausführliche Antwort. Sie hatten recht, als ich 'profileTable.reloadData()' entfernte, funktionierte es gut. Ich habe es repariert, indem ich die Zellen ohne "realodData" aktualisiert habe, wie du gesagt hast, und jetzt ist alles in Ordnung. Haben Sie eine Erklärung, warum dieses Verhalten auftritt, wenn 'reloadData' verwendet wird? – Codey

+1

Wenn Sie 'reloadData()' starten, deaktiviert die Tabellenansicht die Benutzerinteraktion für sich. Die Zellen geben dann false für 'beeFirstResponder()' zurück. In Ihrem Fall wird die zweite Zelle nicht zum Ersthelfer. Wenn Sie dann eine neue Zelle auswählen, gibt es keinen 'reloadData()' - Aufruf, da die vorherige Zelle nicht zum Erstbeantworter geworden ist. DedEndEditing() (wo sich das Neuladen befindet) wird nicht aufgerufen. Aus diesem Grund kann die dritte Zelle bearbeitet werden. Ich bin mir nicht sicher, warum die Tastatur auf dem Bildschirm bleibt, wenn die Bearbeitung nicht verfügbar ist - ich hatte erwartet, dass sie abgewiesen wird, wenn das vorherige Textfeld den Erstantragsteller verlässt. – kr45ko

+0

Perfekte Erklärung. Danke vielmals! – Codey

0

Ich glaube, das Problem ist, dass Sie profileTable.reloadData() aufrufen ... Sie sollten wahrscheinlich nur eine Zelle neu laden. Vielleicht wird textFieldDidEndEditing (:) mit dem alten TextField als Parameter aufgerufen, gefolgt von textFieldShouldBeginEditing ( :) für das neue TextField. Das Problem besteht darin, dass Sie alle Zellen am Ende von textFieldDidEndEditing (:) aktualisieren, was bedeutet, dass das TextField, das vom System als Parameter an textFieldShouldBeginEditing ( :) übergeben wird, nicht notwendigerweise dasselbe sein muss, das die entsprechende Zelle enthält. .Es kann sein, dass diese neuen Tastenanschläge zu einem Textfeld gesendet werden, das zu einer Zelle gehört, die sich in der Warteschlange wiederverwendbarer Zellen befindet, d. H. Nicht sichtbar, aber immer noch irgendwo im Speicher vorhanden.

Verwandte Themen