我已经使用了一个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;
}
}
答案 0 :(得分:2)
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
<强>参考强>
Init custom UITableViewCell from nib without dequeueReusableCellWithIdentifier
UITextFields in UITableView, entered values reappearing in other cells
答案 1 :(得分:1)
使用dequeueReusableCellWithIdentifier
时,您的单元格将被重复使用。这意味着当用户滚动tableview
时,移出屏幕的cell
将被重复使用以显示即将移动到屏幕上的cell
的内容。
尽管这有助于节省内存,但它导致的问题是cell
在加载新cell
的内容之前需要准备好显示。
在您的情况下,您似乎需要维护用户在textfield
的{{1}}中输入的值。
因此,为了解决您的问题,如果cell
中没有那么多cells
,只需停止重用tableview
(对每个单元格实例使用alloc-init / new)。从您的代码看,您的单元格少于10个,这将是解决问题的最快方法。
否则,如果有大量单元格,则只要用户在cell
的{{1}}中输入值,就将其保存在textfield
中。并从数组中获取值,并将其设置为cell
方法中的array
。