UITableViewCell 显示意外的蓝色外框

问题描述 投票:0回答:1

问题:

我在 Swift 应用程序中遇到 UITableViewCell 问题。该代码的目的是更改所选单元格的背景颜色,并使其保持选中状态,即使在与右侧视图中的文本视图交互时也是如此。但是,我在选定和聚焦的单元格周围看到了意想不到的蓝色外框。仅当在模拟器上运行应用程序时才会出现此问题。

以下是一些细节:

  • 控制台中没有显示任何错误或警告。
  • 我使用的模拟器是横向的iPad Air(第五代)。
  • 我使用的是 Xcode 版本 14.3 和 Swift 5.7.2。
  • 您能帮我理解为什么会出现这个蓝色外框以及如何解决它吗?

这是代码:

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
    }
}

我尝试过的:

  1. 当我将此 UITableView 放置在 ViewController 中而不使用 UISplitViewController 时,问题没有发生。
  2. 当我注释掉与操作单元格背景颜色相关的代码时,蓝框消失了。

预期行为:

我希望所选单元格的背景颜色发生变化,没有任何意外的蓝色外框。

ios swift uitableview uikit
1个回答
0
投票

您看到的行为是由于 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
调用,因为这会导致背景颜色立即切换回未选定的颜色。

© www.soinside.com 2019 - 2024. All rights reserved.