2017-06-22 10 views
0

UITextFieldを含む約20行のUITableViewがあります。最初にテキストフィールドをタップするとキーボードが開き、このテキストフィールドを編集する準備が整いました。次のテキストフィールドをタップすると(キーボードは常に表示されます)、キーボードはまだ表示されていますが、青色のカーソルは新しいテキストフィールドにはなく、テキストを入力することはできません。しかし、もう一度別のテキストフィールドをタップするとうまくいきます。この現象は交互に発生します。もう1回は動作しません。UITableViewのUITextFieldが最初のレスポンダにならない

デリゲートメソッドtextFieldShouldBeginEditing(_:)は常に呼び出され、編集できます。デリゲートメソッドtextFieldDidBeginEditing(_:)は、編集作業時にのみ呼び出されます。

これは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 
    } 
} 

enableEditing()disableEditing()メソッドのコードでは、クラスFixableTextFieldからです。私はクラスProfileDataからであるsetProperty方法から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() 
} 

抽出のためのテキストフィールドの境界線に

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

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

コードを見ることができるので、私はテキストフィールドが常に有効になっていることがわかります。 profileUpdateBufferは、私はあなたが記述動作を模倣するための小さなプログラムを作った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

私たちがあなたを助けるためにコードを投稿してください。特に、cellForRowAt indexPath関数。あなたのtextFieldsにリスナーをどのように追加しますか? –

+0

ありがとう、もちろん私はします。 – Codey

+0

'textFieldShouldBeginEditing(_ :)'にフィルタリングロジックがありますか?あなたのVCがすべてのテキストフィールドの代理人になるように設定されていることがわかります。デリゲートメソッドの実装内のセルを区別するロジックがありますか? TextFieldデリゲートをセル内で移動して、各セルがそれ自身の責任を負うようにすることができます。 – kr45ko

答えて

1

型です。 問題があなたのtextFieldDidEndEditing(_:)の終わりにリロードテーブルビューデータによって引き起こされるようだ:

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() 
} 

は(はい、あなたの他の細胞はしません、問題の根本的な原因を確認するための実験のためにprofileTable.reloadData()を削除してください更新します)。

visibleCellsの直接セル更新を利用して、これを解決する方法の1つは、textFieldDidEndEditing(_:)です。あなたのデータモデルはprofileUpdateBuffer?です。セルのtitleLabelプロパティとtextFieldプロパティがモデルから手動で更新されるのは、テーブルビューの可視セルプロパティにある場合のみです。

セルをそれに応じてサイズ調整する場合は、テーブルビューの行の高さとbeginUpdates()/endUpdates()の呼び出しを組み合わせて、AutoLayoutとUITableViewAutomaticDimensionを使用します。

キーボードフォーカスを失うことなくダイレクトセル操作やダイナミックセルサイズの更新を達成する方法の詳細については、check the accepted answer on this question私はすでに答えました。

願っています。

+0

詳細な回答をいただきありがとうございます。あなたは正しく、 'profileTable.reloadData()'を削除したところ、うまくいきました。あなたが言ったように、 'realodData'なしでセルを更新することで修正しました。 'reloadData'を使用しているときになぜこの動作が起こっているのか説明していますか? – Codey

+1

'reloadData()'を起動すると、テーブルビューはユーザインタラクションを無効にします。セルは 'becomeFirstResponder()'に対してfalseを返します。あなたの場合、2番目のセルは最初のレスポンダにはなりません。新しいセルを選択すると、前のセルが最初のレスポンダにならなかったので、reloadData()コールがありません。したがって、didEndEditing()(リロードがある場所)は呼び出されません。このため、3番目のセルを編集することができます。私は編集が利用できないときにキーボードがスクリーン上に残っているのかどうかはわかりません - 前のテキストフィールドが最初のレスポンダを辞任したときに、それが解消されることを期待していました。 – kr45ko

+0

完璧な説明。どうもありがとう! – Codey

0

私は、あなたがprofileTable.reloadData()を呼び出すことが問題だと考えています。おそらく、1つのセルだけをリロードするべきです。おそらくtextFieldDidEndEditing(:)は、新しいTextFieldのtextFieldShouldBeginEditing( :)に続いて、古いTextFieldをパラメータとして呼び出されます。問題は、textFieldDidEndEditing(:)の末尾にあるすべてのセルをリフレッシュすることです。つまり、TextFieldがtextFieldShouldBeginEditing( :)のパラメータとしてシステムから渡され、対応するセルに含まれるものと同じである必要はありません。 。これらの新しいキーストロークは、再利用可能なセルのキューにある、つまり表示されないがメモリのどこかにまだ存在するセルに属するTextFieldに送信されることがあります。

関連する問題