[英]In custom Prototype Cell in UITableView, UITextField value replaces with other Prototype Cell
我已经使用了一个UITableView
,我已经使用了2个prototype
单元,现在在那些原型单元格中,我已经使用了1个UITextField
。
现在,当我运行应用程序并在第一个原型单元格中输入值时,我滚动UITableView
,然后第一个原型单元格的文本字段值来到最后一个原型单元格的文本字段值。 所以它每次滚动或向上滚动时都会替换它。 有时它变得空白。
这是我的代码
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0)
{
Client_MobileCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier_MobileCell forIndexPath:indexPath];
cell.lblTitle.text = [arrTitle objectAtIndex:indexPath.row];
cell.txtMobile.placeholder = [arrPlaceholder objectAtIndex:indexPath.row];
// cell.txtMobile.tag = indexPath.row+100;
return cell;
}
else
{
// Client_Common_Cell *cell = (Client_Common_Cell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier_CommonCell forIndexPath:indexPath];
Client_Common_Cell *cell = (Client_Common_Cell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier_CommonCell];
// cell.txtCommon.tag = indexPath.row+100;
cell.delegate = self;
if(indexPath.row == 1 || indexPath.row == 2 || indexPath.row == 3 || indexPath.row == 4){
if(indexPath.row == 2)
cell.txtCommon.secureTextEntry = YES;
else if(indexPath.row == 4){
cell.txtCommon.keyboardType = UIKeyboardTypeEmailAddress;
}
cell.imgArrow.hidden = YES;
cell.btnSelection.hidden = YES;
}
else{
cell.btnSelection.hidden = NO;
cell.imgArrow.hidden = NO;
}
cell.lblTitle.text = [arrTitle objectAtIndex:indexPath.row];
cell.txtCommon.placeholder = [arrPlaceholder objectAtIndex:indexPath.row];
return cell;
}
}
TL; DR(请给我代码)
Github链接: https : //github.com/starkindustries/CustomTableView
问题
正如其他人所指出的, dequeueReusableCellWithIdentifier
将在滚动时重用相同的单元格引用。 看看下面的gif,可以直观地看到这个问题。
gif中的表有20行(比屏幕上可以容纳的行多)。 每行都有一个文本字段。 我分别在“一”,“二”,“三”,“四”中输入一到四行。
正如你所看到的,当我向下滚动时,“两个”,“三个”和“一个”神奇地出现在底部(不需要的行为)。 这是因为当从屏幕滚动并在底部再次重复使用时,这些单元格从顶部出列。
讨论
经过对网络和堆栈溢出的大量研究后,我建议您在文本字段更改时将其存储在数组中。 然后,您可以在cellForRowAt
方法中相应地设置文本字段文本。 @Rob在他的答案中完美地解释了如何使用模型 - 视图 - 控制器模式来解决这个问题: https ://stackoverflow.com/a/38272077/2179970。 我已经在下面的例子中实现了他的建议。
这个怎么运作
textFieldDidChange(_:)
。 textFieldDidChange(_:)
将调用TableViewController的委托方法cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField)
以通知控制器它的文本已更改。 cellForRowAt
它将适当地更新单元格的文本字段内容。 解决方案
协议:
// Protocol from Step 1
protocol CustomCellDelegate: class {
// This is the function that the ViewController will implement
func cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField)
}
自定义UITableViewCell:
class MyTableViewCell: UITableViewCell, UITextFieldDelegate {
// Protocol reference (Step 1)
weak var delegate: CustomCellDelegate?
@IBOutlet weak var textField: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
// (Step 2) Add a "textFieldDidChange" notification method to the text field control.
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
}
// Step 2
func textFieldDidChange(_ textField: UITextField) {
delegate?.cell(cell: self, updatedCustomTextField: textField)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
查看控制器:
class MyTableViewController: UITableViewController, CustomCellDelegate {
var myTexts: [String?]!
override func viewDidLoad() {
super.viewDidLoad()
myTexts = Array(repeating: nil, count: 20)
let nib = UINib(nibName: "MyTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier: "MyTableViewCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("CellForRowAt: " + indexPath.row.description)
let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as! MyTableViewCell
// Step 5: TableView updates cell contents if reused
cell.delegate = self
cell.textField.text = myTexts[indexPath.row]
return cell
}
// MARK: - CustomCellDelegate Method
// Step 3: The cell will call this protocol method to message the controller
func cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField) {
// when the cell tells us that its text field's value changed, update our own model
if let indexPath = tableView.indexPath(for: cell), let string = textField.text {
// Step 4: The controller updates the model:
print("delegate method cell updatedCustomTextField")
myTexts[indexPath.row] = string
}
}
}
结果
我像往前一样在前四行输入相同的“一”,“二”,“三”,“四”。 这一次,表格表现如预期:文本字段内容出现在我放置的位置,它们不会随机消失/出现。
Github Link
以下是该项目的链接: https : //github.com/starkindustries/CustomTableView
参考
从nib初始化自定义UITableViewCell而不使用dequeueReusableCellWithIdentifier
使用dequeueReusableCellWithIdentifier
,将重用您的单元格。 这意味着当用户滚动tableview
,一个cell
,其移出屏幕的将被重用以显示的内容cell
大约是移动到屏幕上。
即使这有助于节省内存,但它导致的问题是在加载新cell
的内容之前, cell
需要准备好显示。
在您的情况下,您似乎需要维护用户在cell
的textfield
中输入的值。
因此,为了解决您的问题,如果tableview
中没有那么多cells
,只需停止重用cell
(对每个单元格实例使用alloc-init / new)。 从您的代码看,您的单元格少于10个,这将是解决问题的最快方法。
否则,如果存在大量单元格,则只要用户在cell
的textfield
中输入值,就将其保存在array
。 并从数组中获取值并将其设置为cellForRowAtIndexPath
方法中的textfield
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.