使用 SearchController 搜索时使用标签栏出现黑屏

Posted

技术标签:

【中文标题】使用 SearchController 搜索时使用标签栏出现黑屏【英文标题】:Getting black screen on using tab bar while searching using SearchController 【发布时间】:2016-05-20 16:58:19 【问题描述】:

我有一个在导航控制器中嵌入标签栏控制器的应用。该应用程序有 2 个选项卡,第一个(搜索)有一个使用 UISearchController 实现的搜索栏。如果我在搜索时从这个选项卡切换到另一个选项卡(下载),那么会发生两件事 -

第二个标签(下载)中的导航栏消失了 当我回到第一个选项卡(搜索)时,它显示黑屏

我已经使用情节提要完成了所有这些工作。

这是我的 SearchViewController

import UIKit
import Alamofire
import SwiftyJSON

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate

    //MARK: Variables
    var papers = [Paper]()
    var filteredPapers = [Paper]()
    let searchController = UISearchController(searchResultsController: nil)

    // MARK: Outlets
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
    @IBOutlet var table: UITableView!
    @IBOutlet weak var loadingMessageLabel: UILabel!
    @IBOutlet weak var retryButton: UIButton!

    //MARK: Actions
    @IBAction func retryButton(sender: UIButton) 
        self.loadingMessageLabel.hidden = false
        self.loadingMessageLabel.text = "While the satellite moves into position..."
        self.activityIndicator.hidden = false
        self.activityIndicator.startAnimating()
        self.retryButton.hidden = true
        self.getPapersData()

    

    // MARK: Table View

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        // If in searching mode, then return the number of results else return the total number
//        if searchController.active && searchController.searchBar.text != "" 
        if searchController.active 
            return filteredPapers.count
        
        return papers.count
    

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 

        let paper: Paper

//        if searchController.active && searchController.searchBar.text != "" 
        if searchController.active 
            paper = filteredPapers[indexPath.row]
         else 
            paper = papers[indexPath.row]
        

        if let cell = self.table.dequeueReusableCellWithIdentifier("Cell") as? PapersTableCell 

            cell.initCell(paper.name, detail: paper.detail)
            print(cell)
            return cell
        

        return PapersTableCell()

    

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
    

    func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? 


        let downloadButton = UITableViewRowAction(style: .Normal, title: "Download")  action, index in

            var url = String(self.papers[indexPath.row].url)
            url = url.stringByReplacingOccurrencesOfString(" ", withString: "%20")
            print(url)
            let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)

            // Spinner in cell

            //            var selectCell = self.table.cellForRowAtIndexPath(indexPath) as? PapersTableCell
            //            selectCell!.downloadSpinner.hidden = false

            // Dismiss the download button
            self.table.editing = false

            Alamofire.download(.GET, url, destination: destination).response  _, _, _, error in
                if let error = error 
                    print("Failed with error: \(error)")
                 else 
                    print("Downloaded file successfully")
                
                //                selectCell?.downloadSpinner.hidden = true
            

        

        downloadButton.backgroundColor = UIColor(red:0.30, green:0.85, blue:0.39, alpha:1.0)


        return [downloadButton]

    

    func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool 
        // the cells you would like the actions to appear needs to be editable
        return true
    

    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
        // you need to implement this method too or you can't swipe to display the actions
    

    // MARK: Search

    func filterContentForSearchText(searchText: String, scope: String = "All") 
        filteredPapers = papers.filter  paper in
            let categoryMatch = (scope == "All") || (paper.exam == scope)
            return  categoryMatch && paper.name.lowercaseString.containsString(searchText.lowercaseString)
        

        table.reloadData()
    

    func updateSearchResultsForSearchController(searchController: UISearchController) 
        let searchBar = searchController.searchBar
        let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
        filterContentForSearchText(searchController.searchBar.text!, scope: scope)

    

    func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) 
        filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
    

    // MARK: Defaults

    override func viewDidLoad() 
        super.viewDidLoad()

        self.getPapersData()

        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        definesPresentationContext = true
        table.tableHeaderView = searchController.searchBar
        searchController.searchBar.scopeButtonTitles = ["All", "ST1", "ST2", "PUT", "UT"]
        searchController.searchBar.delegate = self
        activityIndicator.startAnimating()


    

    override func viewWillDisappear(animated: Bool) 
//        if searchController.active 
            self.searchController.resignFirstResponder()
//        
    





    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    // MARK: API call

    func getPapersData()
        Alamofire.request(.GET, "http://silive.in/bytepad/rest/api/paper/getallpapers?query=")
            .responseJSON  response in

                self.activityIndicator.stopAnimating()
                self.activityIndicator.hidden = true

                // If the network works fine
                if response.result.isFailure != true 

                    self.loadingMessageLabel.hidden = true
                    self.table.hidden = false
                    //print(response.result)   // result of response serialization

                    let json = JSON(response.result.value!)

                    for item in json 
                        // Split the title on the . to remove the extention
                        let title = item.1["Title"].string!.characters.split(".").map(String.init)[0]
                        let category = item.1["ExamCategory"].string
                        let url = item.1["URL"].string
                        let detail = item.1["PaperCategory"].string

                        let paper = Paper(name: title, exam: category!, url: url!, detail: detail!)
                        self.papers.append(paper)

                    
                    self.table.reloadData()

                
                    // If the network fails
                else 
                    self.retryButton.hidden = false
                    self.loadingMessageLabel.text = "Check your internet connectivity"
                

        
    



这是我的 DownloadViewController

import UIKit
import QuickLook

class DownloadViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, QLPreviewControllerDataSource 

    var items = [(name:String, url:String)]()

    @IBOutlet weak var downloadsTable: UITableView!

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return items.count
    

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 

        print(items[indexPath.row].url)

//        performSegueWithIdentifier("DocumentViewSegue", sender: items[indexPath.row].url)

        let previewQL = QLPreviewController() // 4
        previewQL.dataSource = self // 5
        previewQL.currentPreviewItemIndex = indexPath.row // 6
        showViewController(previewQL, sender: nil) // 7

    

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 

        if let cell = self.downloadsTable.dequeueReusableCellWithIdentifier("Download Cell") as? DownloadsTableCell 

            cell.initCell(items[indexPath.row].name, detail: "", fileURL: items[indexPath.row].url)

            return cell
        

        return DownloadsTableCell()

    

    func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
        if editingStyle == UITableViewCellEditingStyle.Delete 

//            let fileManager = NSFileManager.defaultManager()
//            
//            // Delete 'hello.swift' file
//            
//            do 
//                try fileManager.removeItemAtPath(String(items[indexPath.row].url))
//            
//            catch let error as NSError 
//                print("Ooops! Something went wrong: \(error)")
//            

            items.removeAtIndex(indexPath.row)
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
        
    


    override func viewDidAppear(animated: Bool) 

        items.removeAll()

        let documentsUrl =  NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!

        // now lets get the directory contents (including folders)
        do 
            let directoryContents = try NSFileManager.defaultManager().contentsOfDirectoryAtURL(documentsUrl, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions())
//            print(directoryContents)

            for var file in directoryContents 
                print(file.lastPathComponent)
                print(file.absoluteURL)

                // Save the data in the list as a tuple
                self.items.append((file.lastPathComponent!, file.absoluteString))
            

         catch let error as NSError 
            print(error.localizedDescription)
        

        downloadsTable.reloadData()
    

    // MARK: Preview

    func numberOfPreviewItemsInPreviewController(controller: QLPreviewController) -> Int 
        return items.count
    

    func previewController(controller: QLPreviewController, previewItemAtIndex index: Int) -> QLPreviewItem 
        return NSURL(string: items[index].url)!
    

    override func viewDidLoad() 
        super.viewDidLoad()


        // Do any additional setup after loading the view.


    

    override func viewWillAppear(animated: Bool) 
        //do something

        super.viewWillAppear(true)


    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    
    */



【问题讨论】:

【参考方案1】:

看起来您的UISearchController 附加到的视图已从视图层次结构中删除。当您开始搜索时,您可以将UISearchController 视为模态呈现,definesPresentationContext 属性指示哪个UIViewController 将呈现它(more on this)。

解决此问题的方法之一是重新配置您的故事板,以便每个选项卡都有自己的UINavigationController(以防两者都需要):

而不是(我怀疑你现在拥有的):

如果您想在选项卡切换时关闭UISearchController,请将此覆盖添加到ViewController

override func viewWillDisappear(animated: Bool) 
    super.viewWillDisappear(animated)
    searchController.active = false

【讨论】:

导航控制器嵌入标签栏控制器时遇到了同样的问题。带有导航的视图还包含一个搜索栏。我不需要更改情节提要中的任何内容,只需设置self.definesPresentationContext = true,谢谢! 在 viewDidLoad 中设置 self.definesPresentationContext = true 为我解决了这个问题。并且每个标签都有一个单独的UINavigationController @Hendrix 我的配置和你的一样,但这对我没有帮助。我在视图确实加载时以编程方式实现了搜索控制。

以上是关于使用 SearchController 搜索时使用标签栏出现黑屏的主要内容,如果未能解决你的问题,请参考以下文章

除非我在搜索栏中点击,否则 SearchController 不会显示未过滤的结果

UINavigationBar变成白色,在iOS 13中使用navigationItem.searchController时不会关闭

searchController 在单击搜索项时消失

当 searchController 处于活动状态时,UIButton 不起作用?

SearchController 不搜索自定义 UITableViewCells

使用 SearchController 后的 DidSelect 导致快速崩溃