当我在 UITableView 中更改 UITextField 的文本颜色时,当我滚动时该颜色已应用于另一个 UITextfield

When I change the text color of UITextField inside a UITableView, the color has applied to another UITextfield when I scroll

我真的不明白为什么会这样。如果文本已更改,我正在更改 UITableView 内的 UITextField 的文本颜色,但是当我向下或向上滚动 tableView 时,其他 UITextField 会更改文本颜色。 如何解决这个问题?

这是我的代码和问题的一些截图:

import Foundation
import UIKit

private let reuseIdentifier = "ApcGenericCell"
private let portIdentifier = "ApcPortCell"
private let addressIdentifier = "ApcAddressCell"

class MyViewController: UIViewController {

    private var tableView: UITableView!

    private var bottomConstraint: NSLayoutConstraint!
    private var newBottomConstraint: NSLayoutConstraint!

    var apc = [Apc]()

    override func viewDidLoad() {
        super.viewDidLoad()

        // configure the table view for the left menu
        configureTableView()
    }

    private func configureTableView() {
        tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = 60

        tableView.register(UINib(nibName: "ApcGeneric", bundle: nil), forCellReuseIdentifier: reuseIdentifier)
        tableView.register(UINib(nibName: "ApcPortAt", bundle: nil), forCellReuseIdentifier: portIdentifier)
        tableView.register(UINib(nibName: "ApcIpAddress", bundle: nil), forCellReuseIdentifier: addressIdentifier)
        self.view.addSubview(tableView)
        tableView.backgroundColor = .clear

        tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: view.frame.height / 8).isActive = true
        tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: view.frame.width / 8).isActive = true
        tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -(view.frame.width / 8)).isActive = true
        bottomConstraint = tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -(view.frame.height / 8))
        bottomConstraint.isActive = true

        tableView.alwaysBounceVertical = false
        tableView.tableFooterView = UIView(frame: .zero)

        // register for notifications when the keyboard appears and disappears:
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(note:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(note:)), name: UIResponder.keyboardWillHideNotification, object: nil)

        NotificationCenter.default.addObserver(self, selector: #selector(receivedMessage), name: Notification.Name("ReceivedMessage"), object: nil)

        apc = ApcSection.emptySection()
        self.tableView.reloadData()
    }

    @objc func receivedMessage() {
      DispatchQueue.global(qos: .default).async {
        ApcSection.fetchData(map: self.apcConfig, { (apcResult) in
          self.apc = apcResult

          DispatchQueue.main.async {
              self.tableView.reloadData()
          }
       })
      }
    }

    // Handle keyboard frame changes here.
    // Use the CGRect stored in the notification to determine what part of the screen the keyboard will cover.
    // Adjust our table view's bottomAnchor so that the table view content avoids the part of the screen covered by the keyboard
    @objc func keyboardWillShow(note: NSNotification) {
        // read the CGRect from the notification (if any)
        if let newFrame = (note.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if bottomConstraint.isActive {
                bottomConstraint.isActive = false
                newBottomConstraint = tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -newFrame.height)
                newBottomConstraint.isActive = true
                tableView.updateConstraints()
            }
        }
    }

    // User dismiss the keyboard
    @objc func keyboardWillHide(note: NSNotification) {
        newBottomConstraint.isActive = false
        bottomConstraint.isActive = true
        tableView.updateConstraints()
    }

    @objc func textHasChanged(sender: UITextField) {
        let cell = sender.superview?.superview as! UITableViewCell
        let indexPath = tableView.indexPath(for: cell)

        if let index = indexPath?.row {

            if let _ = apc[index] {
                // change textColor if the value has been changed
              if sender.text != apc[index]!) {
                    sender.textColor = .systemRed
                } else {
                    sender.textColor = .myBlue
                }
            }
        }
    }
}

extension MyViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return apc.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: portIdentifier, for: indexPath) as! ApcPortAt
            cell.selectionStyle = .none
            return cell
        } else if indexPath.row == 7 || indexPath.row == 9 {
            let cell = tableView.dequeueReusableCell(withIdentifier: addressIdentifier, for: indexPath) as! ApcIpAddress
            cell.selectionStyle = .none
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! ApcGeneric
            cell.value.text = apc[indexPath.row]
            cell.value.delegate = self
            cell.value.addTarget(self, action: #selector(textHasChanged(sender:)), for: .editingChanged)
            cell.selectionStyle = .none
            return cell
        }
    }
}

Normal View

Editing

Scroll down after editing

Return to the top

您有 2 种可能的解决方案 1. 应用 UITableViewDataSource 委托的 cellForRowAt 中的更改。 2. 子类化 UITableViewCell 并覆盖 prepareForReuse(),您可以在其中进行更新。并且不要忘记在 table 视图中注册单元格子类。 我认为解决方案 #1 更简单

在 UITableView dequeueReusableCell 中-每个 UITableViewCell 将被多次使用不同的数据(图像)。
在您的情况下,当您滚动时,位于 IndexPath(row: x, section: 0) 的单元格被显示在顶部的另一个单元格重用。例如:带有红色文本的单元格 -> 这个单元格 x 有红色文本,因为你没有为它重置文本颜色
解决方案:

let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! ApcGeneric
    cell.value.text = apc[indexPath.row]
    if index == selectedIndex { // condition to red text
        cell.value.textColor = .systemRed
    } else {
        cell.value.textColor = .myBlue
    }
    cell.value.delegate = self
    cell.value.addTarget(self, action: #selector(textHasChanged(sender:)), for: .editingChanged)
    cell.selectionStyle = .none
    return cell