参考我对提供的初始代码和代码的评论。
许多开发人员以自然的方式实现UITableViewDatasource 方法。
在cellForRowAtIndexPath 中放入一个条件switch/case 块并依赖于indexPath.row 出列并返回可重用单元格。这没关系,但这也意味着您需要再将一个switch/case 块放入heightForRowAtIndexPath 并可能放入numberOfRowsInSection 和didSelectRowAtIndexPath。
如果您需要更改表格视图中单元格的顺序,或者需要在现有单元格或其他内容之间插入新单元格,该怎么办?这导致对现有代码的重大重写。
预定义表格视图(已知行数和顺序)的良好做法是创建一个描述表格视图单元格的对象,并从所有UITableViewDatasource、UITableViewDelegate 方法访问它。该对象还可以用于存储单元格中动态元素的值,并可以相应地更新。
假设它是一个 NSDictionary 的数组(如果我们决定在其中存储数据,则可变一次)。
let cellsData : [[String: String]] = [["type": "TextField","value": ""], ["type": "DatePicker","value": ""], ["type": "TextField","value": "Default Value"]]
在您的UITableViewDatasource,UITableViewDelegate 方法中,您使用indexPath.row 访问您的cellsData 数组,获取NSDictionary 对象解析它,并根据“类型”键的值,将适当的单元格出列。您还必须在任何地方使用 switch/case 块,但您检查来自 cellsData Object 的值而不是 indexPath.row 本身。所以你可以通过更新cellsData 对象来更新你的tableview。你也可以把height放进去等等。
我看到您保留了来自 tableview 中出列的单元格的引用,以便访问它们以检索数据,但如果您将所有实际数据都存储在 cellsData 对象中,则不需要这样做。
如何实现?收听单元格内的事件。创建自定义事件,并从单元格触发它们。
要创建自定义事件,您需要创建自定义delegate 类(参考Implementing a Delegate for a Custom Class)
Swift 的概念与 Objective-C 非常相似。首先我们需要创建委托协议类:
protocol BigTextCellDelegate {
func controller(controller: BigTextCell, textFieldDidEndEditingWithText: String, atIndex: Int)
}
然后你需要在你的自定义单元类中声明一个委托属性。
var delegate: BigTextCellDelegate?
现在你需要在你的tableview类中实现它,首先让你的tableview类在某种程度上符合BigTextCellDelegate协议。
class DetailsNewTaskViewController: UITableViewController, BigTextCellDelegate {
...
}
那我们需要实现BigTextCellDelegate,只要在DetailsNewTaskViewController里面放一个方法即可。
func controller(controller: BigTextCell, textFieldDidEndEditingWithText: String, atIndex: indexRow) {
// @todo: update `cellsData` at indexRow with `textFieldDidEndEditingWithText` text
}
现在您需要将您的自定义单元格列出到UITextFieldDelegate 事件并触发我们的自定义BigTextCellDelegate 事件。
首先你需要让它符合UITextFieldDelegate协议,然后在初始化的时候赋值,你可以在Storyboard中实现。
class BigTextCell: UITableViewCell, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
var Int: rowIndex
var delegate: BigTextCellDelegate?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
textField.delegate = self
}
func textFieldDidEndEditing(textField: UITextField) {
delegate?.controller(self, textFieldDidEndEditingWithText: textField.text, atIndex: rowIndex)
}
}
BigTextCellDelegate 类型的委托属性是可选的,因为我们不能确定它是否为 nil。
现在你需要分配你的tableview来监听BigTextCellDelegate事件。
cellForRowAtIndexPath,输入:
cell = tableView.dequeueReusableCellWithIdentifier(...)
cell.delegate = self
cell.rowIndex = indexPath.row
// @todo: 从 cellsData 数组中获取数据并将其分配回 cell.textField.text
就是这样。
至于 DatePicker 和其他单元格。你可以用同样的方法来做。
从单元格内部分配给 DatePicker 的 valueChanged 并触发新的自定义委托协议上的方法。
datePicker.addTarget(self, action: Selector("dataPickerChanged:"), forControlEvents: UIControlEvents.ValueChanged)
func datePickerChanged(datePicker:UIDatePicker) {
// @todo: trigger event
}