swift 可扩展ViewCell显示意外的蓝色外框

mcdcgff0  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(109)

问:
我的Swift应用程序中的UITableViewCell遇到问题。代码的目的是更改所选单元格的背景颜色,并使其保持选中状态,即使在与右侧视图中的文本视图交互时也是如此。但是,我在所选单元格和焦点单元格周围看到了意外的蓝色外框。此问题仅在模拟器上运行应用程序时发生。
以下是一些详细信息:

  • 控制台中未显示任何错误或警告。
  • 我正在使用的模拟器是iPad Air(第5代)在横向方向.
  • 我使用的是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.当我在不使用UISplitViewController的情况下将此UITableView放置在ViewController中时,未出现此问题。
1.当我注解掉与操作单元格背景色相关的代码时,蓝色框架消失了。
预期行为:
我希望所选单元格的背景色发生变化,但没有任何意外的蓝色外框。

flvlnr44

flvlnr441#

您看到的行为是由于iOS 13的更改:
当单元格高亮显示或被选中时,ContentView类不再更改contentView及其任何子视图的backgroundColor或isOpaque属性。如果您在contentView内部(包括)单元格的任何子视图上设置不透明的backgroundColor,则单元格高亮显示或被选中时的外观可能会受到影响。
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调用,因为这将导致背景颜色立即切换回未选择的颜色。

相关问题