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
并且可能放入 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
对象解析它,并依赖于值"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
}
在我的 iOS 应用程序中,我有一个包含许多单元格的 UITableViewController,其中一些单元格包含一个 UITextField,以便用户可以插入文本。 "problem" 是,如果在右侧单元格中输入文本后,用户向下滚动 table 然后向上滚动,那么这些单元格将再次初始化,文本将再次变为空白。有没有办法防止这种情况?这样只有当 table 向下滚动时才会初始化单元格...谢谢
参考我对初始代码的评论和提供的代码。
许多开发人员以自然的方式实现 UITableViewDatasource
方法。
在 cellForRowAtIndexPath
中放入一个条件 switch/case
块并依赖于 indexPath.row
出列和 return 可重用单元格。这没关系,但这也意味着您需要将另一个 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
对象解析它,并依赖于值"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
}