繁体   English   中英

在UITableView中的自定义Prototype Cell中,UITextField值替换为其他Prototype Cell

[英]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。 我已经在下面的例子中实现了他的建议。

这个怎么运作

  1. 首先,您将设置一个协议,以便自定义UITableViewCell( 视图 )可以将消息发送回ViewController以通知它其文本字段已更改。 ViewController将实现该协议。 该单元将调用协议方法。
  2. 您应用的用户将输入文字。 这将在自定义UITableViewCell类中触发textFieldDidChange(_:)
  3. textFieldDidChange(_:)将调用TableViewController的委托方法cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField)以通知控制器它的文本已更改。
  4. 控制器将更新其文本数组( 模型 )以保存更改。
  5. 如果需要重用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

UITextFields在UITableView中,输入的值重新出现在其他单元格中

UITextField在UITableViewCell中并在模态视图中进行验证

使用dequeueReusableCellWithIdentifier ,将重用您的单元格。 这意味着当用户滚动tableview ,一个cell ,其移出屏幕的将被重用以显示的内容cell大约是移动到屏幕上。

即使这有助于节省内存,但它导致的问题是在加载新cell的内容之前, cell需要准备好显示。

在您的情况下,您似乎需要维护用户在celltextfield中输入的值。

因此,为了解决您的问题,如果tableview中没有那么多cells ,只需停止重用cell (对每个单元格实例使用alloc-init / new)。 从您的代码看,您的单元格少于10个,这将是解决问题的最快方法。

否则,如果存在大量单元格,则只要用户在celltextfield中输入值,就将其保存在array 并从数组中获取值并将其设置为cellForRowAtIndexPath方法中的textfield

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM