iOS模态弹出VC中UISearchBar文字颜色设置无效问题
UISearchBar跨控制器颜色污染问题修复
现有项目结构
- 根控制器为
UITabBarController,其第二个索引页是嵌套在UINavigationController中的视图控制器A - 视图控制器A上设置两个按钮,对应两个跳转逻辑:
- 第一个按钮点击后模态弹出(modal present)包含
UITableView的视图控制器B,B的tableView表头为UISearchController的searchBar - 第二个按钮点击后push跳转至视图控制器C,C中已将自身searchBar的文字颜色设置为白色
- 第一个按钮点击后模态弹出(modal present)包含
问题复现规则
- 直接从A模态弹出B时,B内
searchController.searchBar的文字颜色为黑色,符合预期 - 若先从A push进入C,再pop返回A,之后再模态弹出B,此时B的searchBar文字颜色会变为和C一致的白色,不符合预期
已尝试无效方案
- 在
viewDidLoad生命周期中添加颜色设置代码,无效果:
if #available(iOS 13.0, *) { searchController.searchBar.searchTextField.textColor = UIColor(named: "supportDarkest") } searchController.searchBar.tintColor = UIColor(named: "supportDarkest")
- 在
viewWillAppear生命周期中添加颜色设置代码,仍无效果:
override func viewWillAppear(_ animated: Bool) { if #available(iOS 13.0, *) { searchController.searchBar.searchTextField.textColor = UIColor(named: "supportDarkest") searchController.searchBar.tintColor = UIColor(named: "supportDarkest") searchController.searchBar.tintColorDidChange() } }
问题根因
这个问题是UIKit的UISearchBar全局外观缓存机制导致的:如果C页面设置searchBar颜色时误用了全局UIAppearance代理、或者系统在C页面展示时缓存了searchBar的文字颜色配置,后续新创建的searchBar会默认读取这份缓存配置。而viewDidLoad、viewWillAppear的执行时机早于searchBar内部加载输入框、拉取全局配置的时机,手动设置的颜色会被系统后续的默认配置覆盖,所以无法生效。
可落地修复方案
方案1:在B控制器多时机强制设置颜色,覆盖系统默认配置
在B控制器中补全两个设置时机,确保系统加载完searchBar组件后颜色能被正确赋值:
// 1. 布局完成后设置 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() updateSearchBarTextColor() } // 2. 搜索框即将激活时设置(实现UISearchControllerDelegate协议) func willPresentSearchController(_ searchController: UISearchController) { updateSearchBarTextColor() } // 抽离统一的颜色设置方法 private func updateSearchBarTextColor() { guard #available(iOS 13.0, *) else { return } let targetColor = UIColor(named: "supportDarkest") ?? .black searchController.searchBar.searchTextField.textColor = targetColor searchController.searchBar.tintColor = targetColor searchController.searchBar.searchTextField.layoutIfNeeded() }
方案2:从根源切断全局污染
绝大多数同类颜色串用问题,都是因为设置C页面searchBar颜色时用了全局外观修改,没有在C页面退出时恢复配置。按以下规则修改C页面代码即可彻底避免污染:
- 不要用全局
UIAppearance修改searchBar文字颜色,仅针对C页面当前的searchBar实例设置白色 - 在C页面的
viewWillDisappear中恢复全局searchBar的默认文字颜色
// C页面中修改:不要用全局appearance设置颜色,仅改当前实例 // 错误写法(会污染全局): // UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [.foregroundColor: UIColor.white] // 正确写法(仅作用于当前C页面的searchBar) override func viewDidLoad() { super.viewDidLoad() if #available(iOS 13.0, *) { searchController.searchBar.searchTextField.textColor = .white } } // C页面即将消失时,恢复全局默认配置 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) guard #available(iOS 13.0, *) else { return } UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [ .foregroundColor: UIColor(named: "supportDarkest") ?? .black ] }
提示:优先用方案2处理,从根源避免全局外观污染,后续其他页面新增searchBar也不会再出现颜色异常问题。
内容的提问来源于stack exchange,提问作者Yoel Jimenez del valle
相关产品推荐
相关产品推荐

