UISearchController 关闭时屏幕滞后
Screen lags when UISearchController dismissed
预期:
点击 UIButton 时,显示 viewcontroller 模态,其中包含搜索控制器和带结果的表格视图。
点击列表中的项目时,将搜索栏的文本更改为所点击的内容,然后关闭 viewcontroller 回到原来的状态,现在 UIButton 设置为该文本。
实际:
UIButton 调用 segue 到 searchViewController。
searchViewController 显示并正确配置 searchController 和 tableView。
点击单元格调用退出转场,展开到原始屏幕并正确更新 UIButton 和搜索栏中的文本...
但是,展开后出现异常的白屏,这让我抓狂。
已尝试缓解措施:
- 退出 searchController 然后调用 segue
以编程方式
- 在 didSelectRowAt
中调用 self.dismiss(animated: true completion:nil)
- 通过以下方式将解雇放在主线程上:DispatchQueue.main.async { }
- 调用 self.presentingViewController?.dismiss(动画:真)
Video Demo of flashing
代码:
SearchDetailsViewController - Viewcontroller 放松到
import UIKit
class SearchDetailsViewController: UIViewController {
@IBOutlet weak var destinationButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if searchDestination != "" {
destinationButton.setTitle(searchDestination, for: UIControlState.normal)
destinationButton.setTitleColor(UIColor.black, for: UIControlState.normal)
} else {
destinationButton.setTitle("Search Nearby", for: UIControlState.normal)
}
}
@IBAction func unwindToSearchDetailsViewController(segue: UIStoryboardSegue){
}
}
SearchViewController - 问题 child。我目前将 tableview 单元格作为情节提要中的退出 segue。
class SearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate {
@IBOutlet weak var searchResultsTableView: UITableView!
var destinationsObj:[String:[String]] = [:]
var destinations:[String] = []
var defaultDestinations:[String] = ["Search Nearby"]
var filteredDestinations:[String] = ["Search Nearby"]
var shouldShowSearchResults = false
var searchActive:Bool = false
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
defaultDestinations = recentSearches
configureTableView()
configureSearchController()
}
override func viewDidAppear(_ animated: Bool) {
// Show search bar keyboard
searchController.isActive = true
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Configure Functions
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil) //nil lets the view controller also be the search results
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Where to?"
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
searchResultsTableView.tableHeaderView = searchController.searchBar
searchController.delegate = self
}
func configureTableView() {
searchResultsTableView.delegate = self
searchResultsTableView.dataSource = self
//searchResultsTableView.isMultipleTouchEnabled = false
}
// MARK: TableView Delegate Functions
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if shouldShowSearchResults {
return filteredDestinations.count
} else {
return defaultDestinations.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "idCell", for: indexPath)
if shouldShowSearchResults {
cell.textLabel?.text = filteredDestinations[indexPath.row]
} else {
cell.textLabel?.text = defaultDestinations[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40.0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let value = tableView.cellForRow(at: indexPath)?.textLabel?.text {
self.searchController.searchBar.text = value
searchDestination = value
if !recentSearches.contains(value) {
recentSearches.append(value)
}
}
//self.searchController.resignFirstResponder()
// tableView.deselectRow(at: indexPath, animated: false)
// DispatchQueue.main.async {
// self.dismiss(animated: true, completion: nil)
// }
// self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
// MARK: UISearchBar Delegate Functions
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
//self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if let value = searchBar.text {
searchDestination = value
if !recentSearches.contains(value) {
recentSearches.append(value)
}
}
//self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
shouldShowSearchResults = true
if searchText.characters.count > 1 {
return
} else {
if let firstLetter = searchText.characters.first{
print("Typed \(firstLetter)")
getPredictionData(firstLetter:firstLetter.description)
}
}
}
func dismissCurrentView() {
// self.presentingViewController?.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
Screenshot of my storyboard
好吧,我想我 post 答案是为了防止其他人遇到这种情况。
在 ViewDidAppear 中,我将 searchController 设置为活动
searchController.isActive = 真
在我解散之前,我需要将其设置为不活动!
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let value = tableView.cellForRow(at: indexPath)?.textLabel?.text {
self.searchController.searchBar.text = value
searchDestination = value
if !recentSearches.contains(value) {
recentSearches.append(value)
}
}
self.searchController.isActive = false
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
不要执行 segue,尝试直接关闭视图控制器并在关闭之前将呈现视图控制器的 属性 设置为搜索结果
预期:
点击 UIButton 时,显示 viewcontroller 模态,其中包含搜索控制器和带结果的表格视图。
点击列表中的项目时,将搜索栏的文本更改为所点击的内容,然后关闭 viewcontroller 回到原来的状态,现在 UIButton 设置为该文本。
实际:
UIButton 调用 segue 到 searchViewController。 searchViewController 显示并正确配置 searchController 和 tableView。 点击单元格调用退出转场,展开到原始屏幕并正确更新 UIButton 和搜索栏中的文本...
但是,展开后出现异常的白屏,这让我抓狂。
已尝试缓解措施:
- 退出 searchController 然后调用 segue 以编程方式
- 在 didSelectRowAt 中调用 self.dismiss(animated: true completion:nil)
- 通过以下方式将解雇放在主线程上:DispatchQueue.main.async { }
- 调用 self.presentingViewController?.dismiss(动画:真)
Video Demo of flashing
代码:
SearchDetailsViewController - Viewcontroller 放松到
import UIKit
class SearchDetailsViewController: UIViewController {
@IBOutlet weak var destinationButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if searchDestination != "" {
destinationButton.setTitle(searchDestination, for: UIControlState.normal)
destinationButton.setTitleColor(UIColor.black, for: UIControlState.normal)
} else {
destinationButton.setTitle("Search Nearby", for: UIControlState.normal)
}
}
@IBAction func unwindToSearchDetailsViewController(segue: UIStoryboardSegue){
}
}
SearchViewController - 问题 child。我目前将 tableview 单元格作为情节提要中的退出 segue。
class SearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate {
@IBOutlet weak var searchResultsTableView: UITableView!
var destinationsObj:[String:[String]] = [:]
var destinations:[String] = []
var defaultDestinations:[String] = ["Search Nearby"]
var filteredDestinations:[String] = ["Search Nearby"]
var shouldShowSearchResults = false
var searchActive:Bool = false
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
defaultDestinations = recentSearches
configureTableView()
configureSearchController()
}
override func viewDidAppear(_ animated: Bool) {
// Show search bar keyboard
searchController.isActive = true
DispatchQueue.main.async {
self.searchController.searchBar.becomeFirstResponder()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: Configure Functions
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil) //nil lets the view controller also be the search results
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Where to?"
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
searchResultsTableView.tableHeaderView = searchController.searchBar
searchController.delegate = self
}
func configureTableView() {
searchResultsTableView.delegate = self
searchResultsTableView.dataSource = self
//searchResultsTableView.isMultipleTouchEnabled = false
}
// MARK: TableView Delegate Functions
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if shouldShowSearchResults {
return filteredDestinations.count
} else {
return defaultDestinations.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "idCell", for: indexPath)
if shouldShowSearchResults {
cell.textLabel?.text = filteredDestinations[indexPath.row]
} else {
cell.textLabel?.text = defaultDestinations[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40.0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let value = tableView.cellForRow(at: indexPath)?.textLabel?.text {
self.searchController.searchBar.text = value
searchDestination = value
if !recentSearches.contains(value) {
recentSearches.append(value)
}
}
//self.searchController.resignFirstResponder()
// tableView.deselectRow(at: indexPath, animated: false)
// DispatchQueue.main.async {
// self.dismiss(animated: true, completion: nil)
// }
// self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
// MARK: UISearchBar Delegate Functions
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
//self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if let value = searchBar.text {
searchDestination = value
if !recentSearches.contains(value) {
recentSearches.append(value)
}
}
//self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
shouldShowSearchResults = true
if searchText.characters.count > 1 {
return
} else {
if let firstLetter = searchText.characters.first{
print("Typed \(firstLetter)")
getPredictionData(firstLetter:firstLetter.description)
}
}
}
func dismissCurrentView() {
// self.presentingViewController?.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
Screenshot of my storyboard
好吧,我想我 post 答案是为了防止其他人遇到这种情况。
在 ViewDidAppear 中,我将 searchController 设置为活动 searchController.isActive = 真
在我解散之前,我需要将其设置为不活动!
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let value = tableView.cellForRow(at: indexPath)?.textLabel?.text {
self.searchController.searchBar.text = value
searchDestination = value
if !recentSearches.contains(value) {
recentSearches.append(value)
}
}
self.searchController.isActive = false
self.performSegue(withIdentifier: "cancelSearchSegue", sender: self)
}
不要执行 segue,尝试直接关闭视图控制器并在关闭之前将呈现视图控制器的 属性 设置为搜索结果