当我在 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
我真的不明白为什么会这样。如果文本已更改,我正在更改 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 更简单
在您的情况下,当您滚动时,位于 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