UISearchController persisting after segue - ios

I have an app with a UISearchController. This element of the UI is completely set up in code like this:
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.Minimal
searchController.searchBar.frame = CGRectMake(searchController.searchBar.frame.origin.x, searchController.searchBar.frame.origin.y, searchController.searchBar.frame.size.width, 44.0)
I am then adding it to my tableView's tableHeaderView
tableView.tableHeaderView = searchController.searchBar
Everything seems to be working fine, but when it's active and I select an item in my tableView, my app segues to another view controller with the search controller persisting in the view. I'm unsure as to how this is possible since the search controller should be a subview of the table view in another view controller. How can I prevent this from happening?

You can hide the searchController manually by setting the active property to false in prepareForSegue. Add the below code in prepareForSegue()
searchController.active = false
Alternatively, you should add the following line in viewDidLoad() to get the default behaviour
definesPresentationContext = true
From the documentation for definesPresentationContext
A Boolean value that indicates whether this view controller's view is covered when the view controller or one of its descendants presents a view controller.
Discussion
When a view controller is presented, iOS starts with the presenting view controller and asks it if it wants to provide the presentation
context. If the presenting view controller does not provide a context,
then iOS asks the presenting view controller's parent view
controller. iOS searches up through the view controller hierarchy
until a view controller provides a presentation context. If no view
controller offers to provide a context, the window's root view
controller provides the presentation context.
If a view controller returns true, then it provides a presentation
context. The portion of the window covered by the view controller's
view determines the size of the presented view controller's view.
The default value for this property is false.
Important note (from #paulvs in the comments)
Little gotcha. Set definesPresentationContext on the view controller, not the search controller, I think this is worth emphasising.

If you manage your own transitions and use popToViewController to leave the view, provide the context on the searchController instead of the view
searchController.definesPresentationContext = true
or you will get an error
popToViewController:transition: called on <UINavigationController 0x7f984204f800> while an existing transition or presentation is occurring; the navigation stack will not be updated

Related

Navigation controller large title with search controller glitch when push and back controller

When I browse the next controller or the previous one with the non-collapsed search, its remains visible for a few seconds. How can I fix it?
In First controller I use in viewDidLoad:
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.largeTitleDisplayMode = .automatic
In second controller I use in viewDidLoad:
self.navigationItem.largeTitleDisplayMode = .never
GIF USER CASE
click me
EDIT
I tried putting the entry point directly to the navigation peppa controller and the problem recurs.
Storyboard setup
Try with
navigationItem.searchController = yourSearchController
Probably you forgot to check this reference.

First row hidden when table view appears while search controller is active

I'm using UISearchController with a UITableViewController. When I have a search in progress, and I select a row in the table to go to the detail view, and then go back to the table view, the first row of the table is hidden behind the search bar.
I can scroll the first row back into view, but then it just pops back behind the search bar when I let go of the scroll. So frustrating!
In viewDidLoad I have:
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
mainTable.tableHeaderView = searchController.searchBar
Removing definesPresentationContext = true solves the problem, but I need that to prevent the search bar from showing up if the user segues to other view controllers.
I've spent hours searching for a solution and trying different ways to fix the problem.
Is there any way to set the first row of the table so it is below the search bar when the table view re-appears?
I tried setting definesPresentationContext = true in prepareForSegue, but that did not work.
I found a way to solve this problem.
Do not set definesPresentationContext = true
In prepare(for:sender:), add the following. This keeps the search active, but prevents the search bar and keyboard from appearing on the view controller being segued to.
searchController.searchBar.isHidden = true
searchController.searchBar.endEditing(true)
In viewWillAppear, add the following. This makes the search bar visible when the view controller with the search controller comes to the top of the navigation stack. The first row of the table is positioned properly below the search bar.
searchController.searchBar.isHidden = false
In willMove(toParentViewController:), add the following. This cancels any active search, preventing the search bar from appearing on the view controller coming to the top of the navigation stack.
if parent == nil {
searchController.isActive = false
}
This is working for me:
self.extendedLayoutIncludesOpaqueBars = true

Tabbar is not showing up after popToRootViewController

In my application, I hide tabbar by setting hidesBottomBarWhenPushed property of UIViewController. I'm not sure this behavior is designed or not, when I called popToRootViewController to pop all view controller stack, tabbar did not show properly if I pushed same view controller after. Even I tried to show tabbar by setting isHidden property after I called popToRootViewController but it didn't work neither. Weird part is, after tabbar disappeared, I pushed same view controller and I could see the tabbar when I tried to pop the view controller (not popToRootViewController) by using gesture to pop (swipe to pop). Though it disappeared when transition was completed.
FYI, this is step by step to produce this behavior.
init tabbar and navigation controllers on two tabs.
push view controller (hidesBottomBarWhenPushed is true) on one tab's navigation controller
pop all view controller from the navigation controller by calling popToRootViewController
4 change tab index by setting selectedIndex on tabbarController
push the same view controller
How does hidesBottomBarWhenPushed property work in detail to show/hide tabbar?
I'll talk about the problem in my app.
For every pages, I'll edit the self.navigationController?.navigationBar.isHidden and self.tabBarController?.tabBar.isHidden = false to guarantee the state of tabBar and navigationBar in the viewWillAppear.
Sample
// In this viewController, I'll show the navigation bar and hide tab bar
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.isHidden = false
self.tabBarController?.tabBar.isHidden = true
}
The navigationBar and tabBar can keep their state from last view controller when you push a new one or pop a old one. So it will let we set in every view controller to control and ensure its state as I wish.

Present Modal View in Detail View in UISplitViewController

I want to make a behavior like contacts app in iPad with landscape mode.
I'm expecting that a Modal shows in a Detail view when I click upper right add button.
but now if I click upper right add button, the Modal shows in all screen.
what method should I use? showDetailViewController? or presentViewController? I don’t know how to show Modal in only Detail View.
Firstly you need to set detail view controller's property definesPresentationContext = true. So now it defines presentation context. By default view controllers doesn't pay attention to the current context when they are presented therefore you must do viewController.modalPresentationStyle = .CurrentContext
That's how complete method looks like
func adaptivePresentViewController(viewController: UIViewController) {
let detailVC = splitViewController!.viewControllers[1]
detailVC.definesPresentationContext = true
viewController.modalPresentationStyle = .CurrentContext
detailVC.presentViewController(viewController, animated: true, completion: nil)
}

How to make search bar not disappear while scrolling in table view?

I want to make my search bar stop scrolling along with table view. I tried to add search controller into viewForHeaderInSection and it failed.Also I want to try to show original content while search bar active. So I try to do it in viewDidLoad but I don't know how to make it work. Here is my code for both of method.
searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.Prominent
searchController.searchBar.sizeToFit()
tableView.tableHeaderView = searchController.searchBar
definesPresentationContext = true
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
Do you have any suggestion?
Add both the table view and the search view into another view (which becomes the view of your view controller). Then the search view will be completely disconnected from your table view.
Note that if your view controller is currently a table view controller subclass you will need to change that to be a simple view controller subclass.
You are adding the searchbar to the header view. If you want to keep it above your table you can add it to the navigation controller view. How do I use UISearchController in iOS 8 where the UISearchBar is in my navigation bar and has scope buttons?

Resources