Swift中UITableViewCell在UISplitViewController下出现蓝色外框问题
解决UITableViewCell在UISplitViewController中选中后出现蓝色外框的问题
问题描述
Swift应用中,需求为修改UITableView选中单元格的背景色,且在右侧视图的textView交互时保持选中状态,但选中并聚焦的单元格出现意外蓝色外框,该问题仅在iPad模拟器横屏模式下出现。
环境细节
- 控制台无报错或警告
- 使用iPad Air(第5代)模拟器,横屏模式
- Xcode版本14.3,Swift 5.7.2
已尝试操作
- 将UITableView放在不含UISplitViewController的ViewController中时,问题未出现
- 注释掉修改单元格背景色的代码后,蓝色外框消失
解决方案
这个蓝色外框是系统默认的焦点高亮样式,在UISplitViewController结合文本输入控件的场景下,系统会自动给选中的单元格添加焦点状态,和手动修改背景色的逻辑产生冲突。通过以下两步解决:
- 关闭单元格默认焦点样式:给UITableViewCell设置
focusStyle = .custom,阻止系统添加蓝色焦点外框 - 优化选中状态的背景色设置:在
cellForRowAt中根据选中状态直接设置背景色,避免单元格复用导致的状态异常,同时在选中时刷新对应行保证状态正确
修改后的完整代码
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.focusStyle = .custom // 根据选中状态设置背景色 cell.backgroundColor = selectedIndexPath == indexPath ? .systemOrange : .systemYellow return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: false) let oldIndex = selectedIndexPath selectedIndexPath = indexPath // 刷新旧选中行和新选中行,更新背景色 var reloadPaths = [indexPath] if let oldIndex = oldIndex { reloadPaths.append(oldIndex) } tableView.reloadRows(at: reloadPaths, with: .none) } }
效果验证
修改后,选中单元格仅显示自定义的橙色背景色,不会出现蓝色外框,同时右侧textView交互时选中状态保持正常,单元格复用也不会导致状态混乱。
内容的提问来源于stack exchange,提问作者Seigetsu
相关产品推荐
相关产品推荐

