我有以下视图层次结构:
UINavigationController
||
\/
LibraryTableViewController: UITableViewController
||
\/
AlbumsCollectionViewController: UICollectionViewController
||
\/
SongsTableViewController: UITableViewController
我想在
AlbumsCollectionViewController
中找到一个搜索栏,并在SongsTableViewController
中显示一个不同的navigationItem.titleView
中的搜索栏。我设法在
AlbumsCollectionViewController
中添加了一个工作搜索栏,如下所示:class AlbumsCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {
var searchController : UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
initSearchBar()
initNavigationBar()
}
private func initSearchBar() {
self.searchController = UISearchController(searchResultsController: nil)
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = false
searchController.searchResultsController?.view.isHidden = false
searchController.hidesNavigationBarDuringPresentation = false
self.extendedLayoutIncludesOpaqueBars = true
self.definesPresentationContext = true
searchController.searchBar.backgroundColor = UIColor.black
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes([NSAttributedStringKey.foregroundColor : UIColor.white], for: .normal)
self.navigationItem.titleView = searchController.searchBar
navigationItem.titleView?.isHidden = true
}
private func initNavigationBar() {
searchButton.tintColor = UIColor.white
settingsButton.tintColor = UIColor.white
backButton.tintColor = UIColor.white
self.navigationItem.title = "Artists"
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white]
}
@IBAction func SearchButtonTapped(_ sender: Any) {
showSearchBar()
}
private func showSearchBar(){
navigationItem.titleView?.isHidden = false
searchController.isActive = true
}
}
请注意,搜索栏隐藏在
ViewDidLoad()
上,并且按了SearchButtonTapped
方法中所示的按钮时就会显示。现在,我尝试在
SongsTableViewController
中执行相同的操作,但是,点击按钮时(即调用SearchButtonTapped
),搜索栏没有显示,并且我收到以下消息:Warning: Attempt to present <UISearchController: 0x7f8158812b50> on <MyProject.AlbumsCollectionViewController: 0x7f81588023c0> whose view is not in the window hierarchy!
如果我在
searchController.isActive = true
行中添加了注释,则搜索栏将显示,但是即使我点击了它,它也不会处于 Activity 状态。编辑
对不起,如果我不清楚。我在
UISearchController
中有一个单独的SongsTableViewController
。我的意思是我在两个控制器中使用相同的逻辑还请注意,如果我从导航控制器中推送了
SongsTableViewController
(即视图层次结构仅具有2个控制器(UINavigationController => SongsTableViewController),则搜索栏可以正常工作这是
SongsTableViewController
的大部分代码(忽略的无关内容)import UIKit
import os.log
import MediaPlayer
class SongsTableViewController: UITableViewController, UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate ,PlayerDelegate, NowPlayingDelegate, SongCellDelegate, SongsOptionsDelegate {
// MARK: properties
var playerManager: PlayerManager? = nil
var dataManager: DataManager? = nil
var tabVC: TabBarController?
var selectedSong: Song?
lazy var optionsTransitionDelegate = PresentationManager()
lazy var playlistTransitionDelegate = PresentationManager()
var searchController : UISearchController!
@IBOutlet var backgroundView: UIView!
@IBOutlet weak var searchButton: UIBarButtonItem!
@IBOutlet weak var settingsButton: UIBarButtonItem!
var albumID: String?
var artistID: String?
var playlist: Playlist?
var songs = [Song]()
var songIndexMap = [String: Int]()
var filteredSongs = [Song]()
override func viewDidLoad() {
super.viewDidLoad()
self.dataManager = DataManager.getInstance()
self.playerManager = PlayerManager.getInstance()
playlistTransitionDelegate.screenRatio = 2.0 / 3.0
if(self.albumID != nil) {
self.songs = SQLiteManager.getAlbumSongs(albumID: self.albumID!)
} else if(self.artistID != nil) {
self.songs = SQLiteManager.getArtistSongs(artistID: self.artistID!)
} else if (self.playlist != nil) {
self.songs = SQLiteManager.getPlaylistSongs(playlist: self.playlist!)
} else {
dataManager?.songsTableViewController = self
}
for i in 0..<songs.count {
songIndexMap[songs[i].id] = i
}
initSearchBar()
initNavigationBar()
if(songs.count == 0 && (!fullListOfSongs() || fullListOfSongs() && dataManager?.getFullSongsCount() == 0)){
tableView.backgroundView = backgroundView
}
tableView.tableFooterView = UIView()
tabVC = tabBarController as? TabBarController
tabVC?.nowPlayingViewController?.delegate = self
}
private func shouldAutorotate() -> Bool {
return false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return Util.SONG_CELL_HEIGHT
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(isFiltering()) {
return self.filteredSongs.count
} else if (fullListOfSongs()) {
return dataManager!.getFullSongsCount()
}
return self.songs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "SongTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? SongCell else {
fatalError("The dequeued cell is not an instance of SongCell.")
}
var song: Song?
if(fullListOfSongs()) {
if(isFiltering()){
song = self.filteredSongs[indexPath.row]
} else {
song = dataManager?.getSong(index: indexPath.row)
}
} else {
if(isFiltering()){
song = self.filteredSongs[indexPath.row]
} else {
song = self.songs[indexPath.row]
}
}
cell.setAttributes(song: song!)
cell.delegate = self
cell.preservesSuperviewLayoutMargins = false
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
self.tableView.deselectRow(at: indexPath, animated: false)
}
// MARK: - Search Bar
func updateSearchResults(for searchController: UISearchController) {
if (!searchController.isActive) {
hideSearchBar()
tableView.reloadData()
}
if(isSearchBarEmpty()) {
return
}
filterSongs(filter: searchController.searchBar.text!)
tableView.reloadData()
}
private func filterSongs(filter: String) {
if(self.albumID != nil) {
self.filteredSongs = SQLiteManager.getAlbumSongs(albumID: self.albumID!, filter: filter)
} else if(self.artistID != nil) {
self.filteredSongs = SQLiteManager.getArtistSongs(artistID: self.artistID!, filter: filter)
} else if(self.playlist != nil) {
self.filteredSongs = SQLiteManager.getPlaylistSongs(playlist: self.playlist!, filter: filter)
}else {
self.filteredSongs = SQLiteManager.getSongs(filter: filter)
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == "" {
tableView.reloadData()
}
}
private func initSearchBar() {
self.searchController = UISearchController(searchResultsController: nil)
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = false
searchController.searchResultsController?.view.isHidden = false
searchController.hidesNavigationBarDuringPresentation = false
self.extendedLayoutIncludesOpaqueBars = true
self.definesPresentationContext = true
searchController.searchBar.backgroundColor = UIColor.black
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes([NSAttributedStringKey.foregroundColor : UIColor.white], for: .normal)
self.navigationItem.titleView = searchController.searchBar
navigationItem.titleView?.isHidden = true
}
private func initNavigationBar() {
searchButton.tintColor = UIColor.white
if (fullListOfSongs()) {
searchButton.isEnabled = false
dataManager?.buttons.append(searchButton)
}
settingsButton.tintColor = UIColor.white
self.navigationItem.title = "Songs"
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white]
}
@IBAction func SearchButtonTapped(_ sender: Any) {
showSearchBar()
}
private func showSearchBar(){
self.navigationItem.titleView?.isHidden = false
self.searchController.isActive = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
self.searchController.searchBar.becomeFirstResponder()
}
navigationItem.rightBarButtonItems![0].isEnabled = false
navigationItem.rightBarButtonItems![0].image = nil
navigationItem.rightBarButtonItems![1].isEnabled = false
navigationItem.rightBarButtonItems![1].image = nil
}
private func hideSearchBar() {
navigationItem.titleView?.isHidden = true
navigationItem.rightBarButtonItems![0].isEnabled = true
navigationItem.rightBarButtonItems![0].image = UIImage(named: "settings")
navigationItem.rightBarButtonItems![1].isEnabled = true
navigationItem.rightBarButtonItems![1].image = UIImage(named: "search")
}
func isFiltering() -> Bool {
if(searchController == nil){
return false
}
return searchController.isActive && !isSearchBarEmpty()
}
private func isSearchBarEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
private func fullListOfSongs() -> Bool {
return self.playlist == nil && self.albumID == nil && self.artistID == nil
}
}
最佳答案
当我测试时,这工作。我相信问题出在SongsTableViewController
:self.definesPresentationContext = false
。对于推送的View Controller,这应该是true
。 (请参阅docs here)
对于SongsTableViewController
(推动视图控制器),添加以下内容:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.definesPresentationContext = true
}
并将其添加到
AlbumsCollectionViewController
(初始视图控制器)中:override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.definesPresentationContext = false
}
关于ios - 无法显示UISearchController,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50451647/