导航栏中的 SearchController 问题
SearchController issues in Navigation Bar
我正在尝试创建一个搜索栏,当您单击 "Search"(它也在导航栏中)时,它会出现在导航栏的顶部。单击搜索结果会将您带到详细信息页面,搜索栏将在该页面消失。当您单击返回主页 VC 时,搜索栏会重新出现。以为这很简单,但遇到了一些问题。这是我到目前为止所做的
在主屏幕中点击 "Search" 时创建搜索栏VC 我这样做了:
@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)
}
第一期,当你进入详情页面时,它的搜索栏并没有消失。
解决方案:在PrepareForSegue中,我添加了
self.searchController.searchBar.removeFromSuperview()
并将 unwindSegue 替换为委托,以便当用户从详细信息页面返回主页 VC 时,搜索栏会重新添加。主页VC 执行以下操作:
func didDismissDetail() {
self.navigationController?.popViewControllerAnimated(true)
if searchController.active == true {
self.navigationController?.view.addSubview(searchController.searchBar)
}
}
第二期:搜索场景有bug,点击进入详情页面,返回首页VC,点击取消关闭搜索控制器。当您再次单击导航栏中的搜索按钮时,没有任何反应。我收到此错误:由于未捕获的异常 'NSInvalidArgumentException',正在终止应用程序,原因:'Application tried to present modally an active controller .'
解决方案:我添加了这个
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.searchController.searchBar.removeFromSuperview()
}
这有效,但是当移除视图时没有动画。抱歉,我知道有点啰嗦 - 我的问题是:
- 有没有更好的方法来打造这种用户体验?
如果不是,当用户点击“取消”时,您如何动画删除搜索栏
这是一些图片:
而不是使用 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)
}
编辑:
已更改 viewWillAppear
以手动呈现 UISearchBar
而不是使用 showSearchBar
,这样它就不会每次都显示动画。
添加了对 super.viewWillAppear(animated)
的缺失调用
将 UISearchBar
的解除移动到详细视图控制器的 viewWillAppear
,这样搜索就不会在继续之前消失。
使用 NSUserDefaults
(在 prepareForSegue
中)保留了 UISearchBar
的文本,这样它就可以加载到 viewWillAppear
中主视图控制器将搜索设置为之前的内容。
添加了 searchBarKey
常量用作 UISearchBar
文本持久性的键,因此 "Magic String" 不会用于设置和访问保存的文字.
注:你真的应该考虑使用didSelectRowAtIndexPath
来执行segue。
其他选项:如果您希望UISearchBar
在主视图控制器到详细视图控制器的转换同时进行动画处理,您可以使用自定义segue(这将使动画更流畅)。我制作了一个创建此效果的自定义 segue 示例。请注意,您必须将 Interface Builder 中的视图控制器之间的 segue 更改为 "Custom" 类型并成为 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)
}
}
您可以在以下链接中阅读有关自定义转场中代码的更多信息:
希望对您有所帮助!如果您需要详细说明,请询问! :)
对于问题 #1,您可以在 prepare(for:sender:)
中执行 self.searchController.isActive = false
而不是 self.searchController.searchBar.removeFromSuperview()
。当您放松时,这将停用搜索栏。
我正在尝试创建一个搜索栏,当您单击 "Search"(它也在导航栏中)时,它会出现在导航栏的顶部。单击搜索结果会将您带到详细信息页面,搜索栏将在该页面消失。当您单击返回主页 VC 时,搜索栏会重新出现。以为这很简单,但遇到了一些问题。这是我到目前为止所做的
在主屏幕中点击 "Search" 时创建搜索栏VC 我这样做了:
@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)
}
第一期,当你进入详情页面时,它的搜索栏并没有消失。
解决方案:在PrepareForSegue中,我添加了
self.searchController.searchBar.removeFromSuperview()
并将 unwindSegue 替换为委托,以便当用户从详细信息页面返回主页 VC 时,搜索栏会重新添加。主页VC 执行以下操作:
func didDismissDetail() {
self.navigationController?.popViewControllerAnimated(true)
if searchController.active == true {
self.navigationController?.view.addSubview(searchController.searchBar)
}
}
第二期:搜索场景有bug,点击进入详情页面,返回首页VC,点击取消关闭搜索控制器。当您再次单击导航栏中的搜索按钮时,没有任何反应。我收到此错误:由于未捕获的异常 'NSInvalidArgumentException',正在终止应用程序,原因:'Application tried to present modally an active controller .' 解决方案:我添加了这个
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
self.searchController.searchBar.removeFromSuperview()
}
这有效,但是当移除视图时没有动画。抱歉,我知道有点啰嗦 - 我的问题是:
- 有没有更好的方法来打造这种用户体验?
如果不是,当用户点击“取消”时,您如何动画删除搜索栏
这是一些图片:
而不是使用 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)
}
编辑:
已更改
viewWillAppear
以手动呈现UISearchBar
而不是使用showSearchBar
,这样它就不会每次都显示动画。添加了对
super.viewWillAppear(animated)
的缺失调用
将
UISearchBar
的解除移动到详细视图控制器的viewWillAppear
,这样搜索就不会在继续之前消失。使用
NSUserDefaults
(在prepareForSegue
中)保留了UISearchBar
的文本,这样它就可以加载到viewWillAppear
中主视图控制器将搜索设置为之前的内容。添加了
searchBarKey
常量用作UISearchBar
文本持久性的键,因此 "Magic String" 不会用于设置和访问保存的文字.
注:你真的应该考虑使用didSelectRowAtIndexPath
来执行segue。
其他选项:如果您希望UISearchBar
在主视图控制器到详细视图控制器的转换同时进行动画处理,您可以使用自定义segue(这将使动画更流畅)。我制作了一个创建此效果的自定义 segue 示例。请注意,您必须将 Interface Builder 中的视图控制器之间的 segue 更改为 "Custom" 类型并成为 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)
}
}
您可以在以下链接中阅读有关自定义转场中代码的更多信息:
希望对您有所帮助!如果您需要详细说明,请询问! :)
对于问题 #1,您可以在 prepare(for:sender:)
中执行 self.searchController.isActive = false
而不是 self.searchController.searchBar.removeFromSuperview()
。当您放松时,这将停用搜索栏。