Swift: 防止滚动后重新初始化 UITableViewCell 中带有文本的单元格

Swift: prevent cells with text in UITableViewCell from being re-initialized after scrolling

在我的 iOS 应用程序中,我有一个包含许多单元格的 UITableViewController,其中一些单元格包含一个 UITextField,以便用户可以插入文本。 "problem" 是,如果在右侧单元格中输入文本后,用户向下滚动 table 然后向上滚动,那么这些单元格将再次初始化,文本将再次变为空白。有没有办法防止这种情况?这样只有当 table 向下滚动时才会初始化单元格...谢谢

参考我对初始代码的评论和提供的代码。

许多开发人员以自然的方式实现 UITableViewDatasource 方法。 在 cellForRowAtIndexPath 中放入一个条件 switch/case 块并依赖于 indexPath.row 出列和 return 可重用单元格。这没关系,但这也意味着您需要将另一个 switch/case 块放入 heightForRowAtIndexPath 并且可能放入 numberOfRowsInSectiondidSelectRowAtIndexPath.

如果您需要更改表格视图中单元格的顺序,或者需要在现有单元格之间插入新单元格或其他内容,该怎么办。这导致对现有代码的重大重写。

预定义表格视图(已知行的数量和顺序)的良好做法是创建一个描述表格视图单元格的对象并从所有这些 UITableViewDatasourceUITableViewDelegate 方法访问它。该对象还可以用于存储单元格中动态元素的值,并可以相应地进行更新。

假设它是 NSDictionary 的数组(如果我们决定在其中存储数据,则可变一次)。

let cellsData : [[String: String]] = [["type": "TextField","value": ""], ["type": "DatePicker","value": ""], ["type": "TextField","value": "Default Value"]]

在您的 UITableViewDatasourceUITableViewDelegate 方法中,您使用 indexPath.row 访问您的 cellsData 数组,获取 NSDictionary 对象解析它,并依赖于值"type" 键,使适当的单元格出队。您还必须 switch/case 到处阻塞,但是您检查 cellsData 对象的值而不是 indexPath.row 本身。所以你可以更新你的表视图,只需更新 cellsData 对象。你也可以把height放进去等等

我看到您保留来自表视图中出列的单元格的引用,以便访问它们以检索数据,但如果您将所有实际数据都存储在 cellsData 对象中,则不需要这样做。 如何实现?收听单元格内的事件。创建自定义事件,并从单元格中触发它们。

要创建自定义事件,您需要创建自定义 delegate class(参考 Implementing a Delegate for a Custom Class

Swift 概念与 Objective-C 非常相似。首先我们需要创建委托协议 class:

protocol BigTextCellDelegate {
    func controller(controller: BigTextCell, textFieldDidEndEditingWithText: String, atIndex: Int)
}

然后您需要在自定义单元格 class 中声明一个委托 属性。

var delegate: BigTextCellDelegate?

现在你需要在你的 tableview class 中实现它,首先让你的 tableview class 在某种程度上符合 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
}