问题:
我在 Swift 应用程序中遇到 UITableViewCell 问题。该代码的目的是更改所选单元格的背景颜色,并使其保持选中状态,即使在与右侧视图中的文本视图交互时也是如此。但是,我在选定和聚焦的单元格周围看到了意想不到的蓝色外框。仅当在模拟器上运行应用程序时才会出现此问题。
以下是一些细节:
这是代码:
import UIKit
class ViewController: UIViewController {
let splitVC = UISplitViewController(style: .doubleColumn)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let firstVC = MenuViewController()
let secondVC = SecondViewController()
splitVC.viewControllers = [
UINavigationController(rootViewController: firstVC),
UINavigationController(rootViewController: secondVC)
]
splitVC.modalPresentationStyle = .fullScreen
present(splitVC, animated: false)
splitVC.show(.primary)
}
}
class SecondViewController: UIViewController {
private let textView = UITextView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGray
textView.frame = CGRect(x: 100, y: 200, width: 400, height: 100)
view.addSubview(textView)
}
}
class MenuViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let table: UITableView = {
let table = UITableView()
table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
table.backgroundColor = .systemGray5
table.layer.cornerRadius = 10
return table
}()
private var contents = ["aaa", "bbb", "ccc", "ddd", "eee"]
private var selectedIndexPath: IndexPath?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemMint
table.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(table)
let safeArea = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
table.topAnchor.constraint(equalTo: safeArea.topAnchor, constant: 5),
table.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor, constant: -55),
table.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor, constant: 5),
table.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: -5),
])
table.dataSource = self
table.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contents.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
cell.textLabel?.text = contents[indexPath.row]
cell.selectionStyle = .none
cell.backgroundColor = .systemYellow
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
if let selectedIndexPath = selectedIndexPath {
tableView.cellForRow(at: selectedIndexPath)?.backgroundColor = .systemYellow
}
tableView.cellForRow(at: indexPath)?.backgroundColor = .systemOrange
selectedIndexPath = indexPath
}
}
我尝试过的:
预期行为:
我希望所选单元格的背景颜色发生变化,没有任何意外的蓝色外框。
您看到的行为是由于 iOS 13 中的更改造成的:
当单元格突出显示或被选中时,UITableViewCell 类不再更改 contentView 及其任何子视图的 backgroundColor 或 isOpaque 属性。如果您在 contentView 内部(并包括)单元格的任何子视图上设置不透明的背景颜色,则单元格突出显示或选择时的外观可能会受到影响。
Apple 对此给出了解决方案:
解决子视图任何问题的最简单方法是确保它们的backgroundColor设置为nil或clear,并且它们的opaque属性为false。但是,如果需要,您可以重写 setHighlighted(:animated:) 和 setSelected(:animated:) 方法,以便在移至或移出突出显示和选定状态时手动更改子视图上的这些属性。
基于上述内容,一个快速的解决方案是使用
UITableViewCell
的自定义子类(我假设您已经在实际代码中这样做了)。
final class MyCell: UITableViewCell {
override func setHighlighted(_ highlighted: Bool, animated: Bool) { }
override func setSelected(_ selected: Bool, animated: Bool) {
contentView.backgroundColor = selected ? .systemOrange : .systemYellow
}
}
请注意,我设置的是
contentView
的背景颜色,而不是单元格本身,否则它可能无法正常工作。
cellForRowAt
方法将被简化为类似
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MyCell
cell.textLabel?.text = contents[indexPath.row]
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// tableView.deselectRow(at: indexPath, animated: false)
selectedIndexPath = indexPath
}
请注意,我还注释掉了
tableView.deselectRow
调用,因为这会导致背景颜色立即切换回未选定的颜色。