导航栏

时间:2016-06-22 23:03:33

标签: ios swift search uinavigationbar uisearchcontroller

当您点击“搜索”(也在导航栏中)时,我正在尝试创建一个显示在导航栏顶部的搜索栏。单击搜索结果将转到详细信息页面,搜索栏将消失。当您单击以返回到主VC时,搜索栏会再次出现。认为这很简单但遇到一些问题。这就是我到目前为止所做的事情

要在HomeVC中点击“搜索”时创建搜索栏,我就这样做了:

@IBAction func SearchAction(sender: AnyObject) {
        searchController.searchResultsUpdater = self
        searchController.searchBar.delegate = self
        definesPresentationContext = true
        searchController.dimsBackgroundDuringPresentation = false
        searchController.hidesNavigationBarDuringPresentation = false
        self.navigationController?.presentViewController(searchController, animated: true, completion: nil)
}

第1期,当您转到详细信息页面时,搜索栏不会消失。

解决方案:在PrepareForSegue中,我添加了

self.searchController.searchBar.removeFromSuperview()

并将unwindSegue替换为委托,以便当用户从详细信息页面返回到Home VC时,会重新添加搜索栏.HomeVC执行以下操作:

func didDismissDetail() {
    self.navigationController?.popViewControllerAnimated(true)
    if searchController.active == true {
        self.navigationController?.view.addSubview(searchController.searchBar)
    }
}

第二期:您搜索的方案中存在错误,点按以转到详细信息页面,返回主页VC,点按取消以关闭搜索控制器。再次单击导航栏中的“搜索”按钮时,没有任何反应。我收到此错误:由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:'应用程序尝试以模态方式呈现活动控制器。 解决方案:我添加了此

func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    self.searchController.searchBar.removeFromSuperview()        
}

然而,这有效,删除视图时没有动画。对不起,我知道这有点长啰嗦 - 我的问题是:

  1. 是否有更好的方法来创建此用户体验?
  2. 如果没有,当用户点击取消时,如何动画删除搜索栏

    以下是一些图片:

  3. Home Screen After clicking "Search"

2 个答案:

答案 0 :(得分:3)

您应该使用:

,而不是使用self.searchController.searchBar.removeFromSuperview()
navigationController?.dismissViewControllerAnimated(true, completion: nil)`

解雇视图。此外,您应该为您的segue提供标识符,并在prepareForSegue中进行检查。您的实现可能如下所示:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if segue.identifier == "ToDetail" {
      let destination = segue.destinationViewController as! DetailViewController
      navigationController?.dismissViewControllerAnimated(true, completion: nil)
     //Pass Info to Detail View
   }
}

然后在didSelectRowAtIndexPath中使用performSegueWithIdentifier执行您的segue。

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
   performSegueWithIdentifier("ToDetail", sender: self)
}

要允许searchBar重新出现,您可以在主视图控制器上设置一个名为searchBarShouldBeOpen的布尔变量。在SearchAction函数中将此值设置为true,然后在viewWillAppear中使用带有searchBarShouldBeOpen的if语句来决定是否运行SearchAction。另外,请考虑将SearchAction作为常规函数,并将示例中显示的最后一行移动到viewDidLoad。最后,为主视图控制器实现UISearchBarDelegate并覆盖searchBarCancelButtonClicked,并在其中将searchBarShouldBeOpen设置为false。您的主视图控制器看起来像这样:

class ViewController: UIViewController {
 //...Your Variables

 var searchBarShouldBeOpen: Bool = false

 let searchBarKey = "SearchBarText"

 override func viewDidLoad() {
    super.viewDidLoad()
    searchController.searchResultsUpdater = self
    searchController.dimsBackgroundDuringPresentation = false
    definesPresentationContext = true
    searchController.searchBar.delegate = self
    searchController.hidesNavigationBarDuringPresentation = false

    navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Search", style: .Plain, target: self, action: #selector(ViewController.showSearchBar))
  }

  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    if searchBarShouldBeOpen {
       navigationController?.presentViewController(searchController, animated: false, completion: nil)
       searchBarShouldBeOpen = true
       if let previousText = NSUserDefaults.standardUserDefaults().stringForKey(searchBarKey) {
          searchController.searchBar.text = previousText
       }
    }  
  }

  func showSearchBar() {
    navigationController?.presentViewController(searchController, animated: true, completion: nil)
     searchBarShouldBeOpen = true
  }

  override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "ToDetail" {
      let destination = segue.destinationViewController as! DetailViewController
      if searchController.searchBar.text != "" { 
         NSUserDefaults.standardUserDefaults().setValue(searchController.searchBar.text, forKey: searchBarKey)
      }
       //Pass Info
    }
  }
  //Your functions...
}

extension ViewController: UISearchBarDelegate {
   func searchBarCancelButtonClicked(searchBar: UISearchBar) {
     searchBarShouldBeOpen = false
  }
}

在详细信息视图控制器中添加以下内容:

override func viewWillAppear(animated: Bool) {
   super.viewWillAppear(animated)
   navigationController?.dismissViewControllerAnimated(true, completion: nil)
}

<强>编辑:

  1. 更改viewWillAppear以手动显示UISearchBar而不使用动画,而不是使用showSearchBar,以便每次都不会制作动画。

  2. 添加了对super.viewWillAppear(animated)

  3. 的遗失电话
  4. UISearchBar的解雇移至详情视图控制器的viewWillAppear,以便搜索在segue之前不会消失。

  5. 使用UISearchBarNSUserDefaults)保留prepareForSegue的文字,这样就可以将其加载到主广告的viewWillAppear中查看控制器将搜索设置为以前的搜索。

  6. 添加了searchBarKey常量作为UISearchBar文本持久性的关键,因此&#34; Magic String&#34;不会用于设置和访问已保存的文本。

  7. 注意:您应该考虑使用didSelectRowAtIndexPath来执行segue。

    其他选项:如果您希望UISearchBar在将主视图控制器转换为详细视图控制器的同时进行动画处理,则可以使用自定义segue(这将使动画有点流畅)。我创建了一个自定义segue示例来创建此效果。请注意,您必须在Interface Builder中更改视图控制器之间的segue以使其具有类型&#34; Custom&#34;并成为UIStoryboardSegue的以下子类。

    class CustomSegue: UIStoryboardSegue {
    
       override func perform() {
          let pushOperation = NSBlockOperation()
          pushOperation.addExecutionBlock {
             self.sourceViewController.navigationController?.pushViewController(self.destinationViewController, animated: true)
          }
          pushOperation.addExecutionBlock {
            self.sourceViewController.navigationController?.dismissViewControllerAnimated(true, completion: nil)
          }
          pushOperation.queuePriority = .Normal
          pushOperation.qualityOfService = .UserInitiated
          let operationQueue = NSOperationQueue.mainQueue()
          operationQueue.addOperation(pushOperation)
    
       }
    
    }
    

    您可以在以下链接中阅读有关自定义segue中代码的更多信息:

    1. 自定义细分:http://www.appcoda.com/custom-segue-animations/
    2. NSOperation:http://nshipster.com/nsoperation/
    3. 希望这有帮助!如果你需要详细说明,请问! :)

答案 1 :(得分:0)

问题#1,而不是self.searchController.searchBar.removeFromSuperview(),您可以在self.searchController.isActive = false中执行prepare(for:sender:)。当您放松时,这会使搜索栏失效。