🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

1437閲覧

Swiftでカスタムセルのテキストフィールドの値を渡したい

Yuto409

総合スコア3

TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/01/31 09:22

タスクリストを作っています。

tasksをカスタムセルのtaskCellでTaskTableに表示しています。
taskCellの中のTextFieldの値を変更したあと、TableViewを更新すると、TextFieldの変更が適用されていません。
TextFieldの値をどうにかしてtasksに代入させたいのですが、やり方がわかりません。

Swift

1import UIKit 2 3class Task: Identifiable { 4 var id: UUID 5 var taskName: String 6 var isCompleted: Bool 7 8 init(id: UUID, taskName: String, idCompleted: Bool) { 9 self.taskName = taskName 10 self.id = id 11 self.isCompleted = idCompleted 12 } 13}

Swift

1import UIKit 2import SwiftUI 3 4class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate { 5 6 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 7 return tasks.count 8 } 9 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 10 let cell: TaskCell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell 11 cell.taskTextField.delegate = self 12 cell.setItem(task: tasks[indexPath.row]) 13 return cell 14 } 15 16 17 18 19 override func viewDidLoad() { 20 super.viewDidLoad() 21 } 22 23 24 25 26 27 var tasks = [Task]() 28 29 @IBOutlet weak var taskTable: UITableView! 30}

Swift

1import Foundation 2import UIKit 3 4class TaskCell: UITableViewCell, UITextFieldDelegate { 5 var cellTask = Task(id: UUID(), taskName: "", isCompleted: false) 6 @IBOutlet weak var completeButton: UIButton! 7 @IBOutlet weak var taskTextField: UITextField! 8 9 func setItem(task: Task) { 10 cellTask = task 11//TextFieldとButtonにcellTaskの要素を代入する処理 12 } 13 14 @IBAction func completeButon(_ sender: UIButton) { 15//completeButtonの切り替え処理 16 } 17 18}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

どのように作るか次第ですが、たぶん UITextField の処理で混乱されているように思えます。

Swift

1class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate { 2 // 中略 3 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 4 let cell: TaskCell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell 5 cell.taskTextField.delegate = self 6 } 7}

上記のコードでは、

Swift

1cell.taskTextField.delegate = self

と、Delegate に ViewController のインスタンスを入れていますが、そうではなくて、UITableViewCell のインスタンスを代入し、セルの中で処理を行ったほうが簡潔に書けそうな気がします。

つまり、

Swift

1class TaskCell: UITableViewCell, UITextFieldDelegate {

カスタムセルに UITextFieldDelegate を準拠させ、

Swift

1 private lazy var textField: UITextField = { 2 let tf = UITextField() 3 tf.borderStyle = .line 4 5 // ここの self は UITableViewCell 自身 6 tf.delegate = self 7 8 return tf 9 }()

UITableViewCell 内部の UITextField の delegate はセル自身にした上で

Swift

1 2 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 3 label.text = textField.text 4 textField.text = "" 5 task?.taskName = textField.text ?? "" 6 textField.resignFirstResponder() 7 8 return true 9 }

セルの中で UITextFiled の処理を行うといった感じです。


たとえば、こんな感じです(StoryBoard は使っていなので、このままコピーてして実行すると動くと思います)。

Swift

1import UIKit 2 3class Task { 4 var taskName: String 5 6 init(taskName: String) { 7 self.taskName = taskName 8 } 9} 10 11class TaskCell: UITableViewCell, UITextFieldDelegate { 12 private var task: Task? 13 14 override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 15 super.init(style: style, reuseIdentifier: reuseIdentifier) 16 17 setUp() 18 } 19 20 required init?(coder: NSCoder) { 21 fatalError("init(coder:) has not been implemented") 22 } 23 24 private let label = UILabel() 25 26 private lazy var textField: UITextField = { 27 let tf = UITextField() 28 tf.borderStyle = .line 29 30 // ここの self は UITableViewCell 自身 31 tf.delegate = self 32 33 return tf 34 }() 35 36 private lazy var button: UIButton = { 37 let b = UIButton(type: .system) 38 b.setTitle("set", for: .normal) 39 b.backgroundColor = .yellow 40 b.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) 41 42 return b 43 }() 44 45 // ボタンが押されたら、ラベルに UITextField の内容を表示し、UITextFiled は空にし、キーボードを閉じる 46 @objc private func buttonTapped(_ sender: UIButton) { 47 textField.resignFirstResponder() 48 label.text = textField.text 49 task?.taskName = textField.text ?? "" 50 textField.text = "" 51 } 52 53 // コードでカスタムセルを作成しているだけ。 54 private func setUp() { 55 let sv = UIStackView(arrangedSubviews: [label, textField, button]) 56 contentView.addSubview(sv) 57 sv.axis = .vertical 58 sv.spacing = 6 59 60 sv.translatesAutoresizingMaskIntoConstraints = false 61 sv.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor).isActive = true 62 sv.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor).isActive = true 63 sv.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor).isActive = true 64 sv.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor).isActive = true 65 } 66 67 // セルに各要素をセット 68 func setItem(_ task: Task) { 69 self.task = task 70 label.text = task.taskName 71 textField.text = "" 72 } 73 74 // セルの中で UITextFiled の処理を行う 75 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 76 label.text = textField.text 77 textField.text = "" 78 task?.taskName = textField.text ?? "" 79 textField.resignFirstResponder() 80 81 return true 82 } 83} 84 85class ViewController: UIViewController { 86 var data = (1...10).map { _ in Task(taskName: "not set") } 87 88 lazy var tableView: UITableView = { 89 let tv = UITableView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height)) 90 tv.dataSource = self 91 tv.delegate = self 92 93 tv.register(TaskCell.self, forCellReuseIdentifier: "cell") 94 95 return tv 96 }() 97 98 override func viewDidLoad() { 99 super.viewDidLoad() 100 // Do any additional setup after loading the view. 101 102 view.addSubview(tableView) 103 } 104} 105 106extension ViewController: UITableViewDelegate, UITableViewDataSource { 107 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 108 return data.count 109 } 110 111 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 112 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TaskCell 113 114 cell.setItem(data[indexPath.row]) 115 116 return cell 117 } 118}

投稿2021/01/31 21:04

TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yuto409

2021/02/01 13:33

これを参考にコードを書いたところ、自分の思うように動作しました! 本当にありがとうございました。
TsukubaDepot

2021/02/01 13:39

ViewControllerをdelegate にすることも可能ですが、そうなるとどのセルが操作されたのか確認するのが面倒になるので、ここは単純にセル(も独立したインスタンス)に全ても任せる(責務の分離、というのでしょうか)のがわかりやすいかと思います。
guest

0

TableViewを更新すると、TextFieldの変更が適用されていません。

更新したテキストをtasksで変更していないからです。

投稿2021/01/31 13:02

tomato879241

総合スコア133

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問