点击开关UISearchBar时出现位置偏移、宽度异常、动画不符合预期如何解决?
UISearchBar切换状态布局异常修复方案
问题表现
实现UISearchBar的打开和关闭功能时,存在四个异常表现:
- y坐标位置轻微偏移
- 首次打开时宽度变化逻辑和后续不一致
- 状态切换时动画不符合直觉
- 搜索栏初始关闭状态的UI,与打开后再关闭的UI表现不一致
效果演示
组件首次布局子视图时:
首次打开搜索功能时:
关闭搜索栏后:
复现代码
viewDidLoad
override func viewDidLoad() { super.viewDidLoad() initSearchCont() }
initSearchCont
func initSearchCont(){ search.hidesNavigationBarDuringPresentation = false search.loadViewIfNeeded() search.searchResultsUpdater = self search.obscuresBackgroundDuringPresentation = false search.searchBar.enablesReturnKeyAutomatically = false search.searchBar.translatesAutoresizingMaskIntoConstraints = false search.searchBar.returnKeyType = UIReturnKeyType.done definesPresentationContext = false self.view.addSubview(search.searchBar) navigationItem.hidesSearchBarWhenScrolling = false search.searchBar.scopeButtonTitles = ["All", "Pair", "Odd"] search.searchBar.delegate = self search.searchBar.backgroundImage = UIImage() }
viewDidLayoutSubviews
override func viewDidLayoutSubviews() { search.searchBar.frame = CGRect(x: 0, y: 50, width: search.isActive ? 400 : 50, height: search.isActive ? 100 : 50) search.searchBar.placeholder = search.isActive ? "Search" : nil }
searchBar代理方法
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { search.searchBar.endEditing(true) searchBar.resignFirstResponder() } func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { }
问题根源
- 布局逻辑冲突:代码中设置了
search.searchBar.translatesAutoresizingMaskIntoConstraints = false启用自动布局,同时又在viewDidLayoutSubviews中直接修改frame,两种布局方式冲突,导致系统自动修正的frame和手动设置的frame不一致。 - 状态切换无同步动画:搜索激活/关闭状态切换时,没有主动触发带动画的布局更新,系统默认动画和手动frame修改时机不同步,导致首次动画异常、宽度变化不一致。
- 状态同步不完整:点击取消按钮时仅取消了第一响应者,没有将
search.isActive置为false,搜索控制器的状态和UI表现不同步,导致关闭后布局异常。
修复方案
1. 统一布局方式
如果要手动控制frame,将translatesAutoresizingMaskIntoConstraints设置为true,关闭自动布局对frame的干涉:
// 修改initSearchCont中的对应行 search.searchBar.translatesAutoresizingMaskIntoConstraints = true
2. 移除viewDidLayoutSubviews中的动态布局逻辑
仅在初始加载时设置搜索栏的默认frame,不要每次系统触发布局时都覆盖frame设置:
override func viewDidLoad() { super.viewDidLoad() initSearchCont() // 初始设置关闭状态的frame search.searchBar.frame = CGRect(x: 0, y: 50, width: 50, height: 50) } // 清空viewDidLayoutSubviews中的搜索栏frame设置代码 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // 其他原有布局逻辑保留即可 }
3. 在状态切换代理中添加带动画的布局更新
在搜索激活和关闭的代理方法中,主动添加动画包裹,保证动画表现一致:
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { UIView.animate(withDuration: 0.3) { self.search.searchBar.frame = CGRect(x: 0, y: 50, width: 400, height: 100) self.search.searchBar.placeholder = "Search" } } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { // 同步搜索控制器状态 search.isActive = false searchBar.resignFirstResponder() UIView.animate(withDuration: 0.3) { self.search.searchBar.frame = CGRect(x: 0, y: 50, width: 50, height: 50) self.search.searchBar.placeholder = nil } }
内容的提问来源于stack exchange,提问作者Camille Basbous
相关产品推荐
相关产品推荐

