UISearchBar Disappear From UINavigationBar When Use "back swipe" iOS 12 - ios

I have 2 ViewController for both implemented:
let searchBar = UISearchBar()
func viewDidLoad() {
navigationItem.titleView = searchBar
}
When I push second view controller and try go back with swipe gesture, all my navigation items disappearing irrevocably.
Maybe someone has an idea how to fix it?
Images:
SearchBar First VC
https://imgur.com/QJxflWP.png
SearchBar Second VC
https://imgur.com/FUBo0t6.png
NavigationBar When starting back swipe
https://imgur.com/G2FXrnq.png

A navigation item is associated with the view controller. So if you want search bar in both view controllers you have to set the search bar for both the view controllers.
Also, you can use searchController property to show the search bar in the navigation controller. So that you can show the title and search bar in the navigation bar.

A navigation item is associated with the view controller. So if you want to show search bar in both view controllers you have to add it separately in the viewDidLoad method.
And also you can use searchController property to show the search bar in the navigation bar. So that you can show both title and search bar in the navigation bar.

I finally solve this problem by handling UINavigationBarDelegate methods.
Use your own UINavigationController because UINavigationController is the default delegate of UINavigationBar, i don't need to reassign delegate to other class to handle.
implement these code and get the searchField inside of UISearchBar to minor change its frame.
extension YourNavigationController: UINavigationBarDelegate {
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item:
UINavigationItem) -> Bool {
if let inSearchBar = item.titleView as? UISearchBar,
let searchField = inSearchBar.value(forKey: "searchField") as? UIView {
searchField.frame = CGRect(x: 0, y: 0, width: searchField.frame.width + 1, height: 36)
}
}
}
Why i do this is because i found that if the frame of searchField don't change, then the search bar would disappear. It is not a good way to do but a kind of workaround to show the correct view. In iOS 13, i believe we can check to use searchTextField to replace searchField, a property provided by Apple doc.

Related

How to add observer to find navigation bar show and hide

I have MapViewController embedded in a UINavigationController. I push to multiple view controllers from this view controller, pop to MapViewController from these view controllers.
In MapViewController I have google map its top position starts from safeAreaLayoutGuide. I hide and show the navigation controller based on multiple conditions. For example when I show subview1 I hide the navigation bar, when I show subview2 I show the navigation bar, etc...
Now I want to change the mapview top position whenever the navigation bar is visibility is changed.
How to solve this?
I checked UINavigationControllerDelegate. There is no delegate method called when navigation bar is shown/hidden where I can update the mapview top position.
viewDidLayoutSubviews is not called when navigation bar visibility changed.
I want to do this in MapViewController only. Not in pushed view controller from this one.
You can add a property observer to the isHidden property of navigationBar and then observe any changes made, i.e.
var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
self.observer = self.navigationController?.navigationBar.observe(\.isHidden, options: [.new], changeHandler: { (navigationBar, changes) in
if let newValue = changes.newValue {
print(newValue)
topConstraint.constant = newValue ? 0 : self.view.safeAreaInsets.top
}
})
}
When any changes are made in the isHidden property of navigationBar, we'll get a callback in the closure and act accordingly.

navigation controller custom search bar not disappearing?

I created a custom search bar and embedding it in the navigation bar, it appears but after I push another view controller, the search bar does not get replaced with the title of the pushed view controller. The search bar stays persistent throughout all views, instead of getting replaced with a title. Perfect example is Instagram search tab, you search for a person and click on the cell, their profile is pushed and the search bar is replaced with the custom title, back button, etc.
First VC
self.customSearchBar.tag = 4
self.navigationController?.view.addSubview(customSearchBar)
Second VC
if let nav: UINavigationController = self.navigationController {
if let searchBar = nav.view.viewWithTag(4) {
searchBar.removeFromSuperview()
}
}
You shouldn't place the searchbar inside the navigationcontroller view as this view is the same instance on all pushed viewcontrollers.
Add the searchbar to the the depending view controllers ui.
To add a searchbar on navigationBar, this is the way.
self.navigationController?.navigationBar.addSubview(customSearchBar)
To remove it when you push it to other viewController. Write the following code in the secondVC that is pushed inside it's viewDidLoad() function. Also, set the tag of customSearchBar to any number (TAG)
if let nav: UINavigationController = self.navigationController {
let bar: UINavigationBar = nav.navigationBar
if let searchBar = bar.viewWithTag(TAG) {
searchBar.removeFromSuperview()
}
}
In the question, the customSearchBar is added to self.navigationController.view. To remove it, you can do the following:
if let nav: UINavigationController = self.navigationController {
if let searchBar = nav.view.viewWithTag(TAG) {
searchBar.removeFromSuperview()
}
}
Edit:
Adding and removing a UIViewController's view as a subview of other UIViewController
// for adding
let viewController: ViewController = ViewController()
self.addChildViewController(viewController)
self.view.addSubview(viewController.view)
viewController.view.bounds = self.view.bounds // better to use autolayout here
viewController.didMove(toParentViewController: self)
// for removing
if let vc = self.childViewControllers.last {
vc.willMove(toParentViewController: nil)
vc.view.removeFromSuperview()
vc.removeFromParentViewController()
}

conditional showing of uitoolbar

I have a UIViewController that is presented in two ways, either modally or pushed on top of a navigation controller stack. The UIViewController contains a UITableView and a UIToolbar. When presented modally, i needed a way of showing a title for the ViewController, so I added in another UIToolbar, topToolbar. My problem is, whenever I push the UIViewController, I don't need topToolbar anymore, since the navigation tabbar already shows the title. When I set topToolbar's hidden property to true, however, my UITableView is not bound to the bottom of the navigation tab bar and there's space between the UITableView and the navigation tabbar, which doesn't look so good. I tried to call removeFromSuperview() on topToolbar instead of setting its hidden property to true, but that didn't work out, and topToolbar appeared under the navigation bar, and now i have two titles instead of one. Any idea on how this can be done? I can't add pictures, but here's my code for manipulating the appearance of the UIViewController based on whether it's presented modally or pushed on top of the navigation stack:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if itemBought != nil {
cart.items.append(itemBought!)
}
totalView.layer.borderColor = UIColor.grayColor().CGColor
totalView.layer.borderWidth = 0.5
totalLabel.text = "$" + String(format: "%.2f", cart.getTotal())
if let navBar = self.navigationController?.navigationBar {
//hide toolbar and tabbar
topToolbar.removeFromSuperview()
self.tabBarController?.tabBar.hidden = true
//hide shop button
var bottomItems: [UIBarButtonItem] = bottomToolbar.items as! [UIBarButtonItem]
if let index = find(bottomItems, shopToolbarButton) {
bottomItems.removeAtIndex(index)
}
bottomToolbar.items = bottomItems
}
}
I should also mention that i have a constraint on the UITableView that's basically: distance between UItableView.top and Top Layout Guide.Bottom is <= to the height of topToolbar, which is 44.
Any ideas?
When you present the View Controller modally, why not put it in a UINavigation Controller?
let navigationController = UINavigationController(rootViewController: myViewControllerInstance)
self.navigationController?.presentViewController(navigationController, animated: true, completion: { () -> Void in
//do something here when animation is complete if you want
})

iOS: how to add a search bar on navigation bar programmatically on a button press?

I know how to initialise the UIsearchcontroller by doing this:
let searchResultsController = UITableViewController(style: .Plain) as UITableViewController
searchResultsController.tableView.delegate = self
searchResultsController.tableView.dataSource = self
searchController = UISearchController(searchResultsController: searchResultsController)
so,
I have a button on navigation bar and on press I want to display SearchBar using UISearchController and then dismiss the search bar on tapping again on the search button or empty space of screen.
According to documentation, changing active property of search controller will move search bar to navigation bar

Disappearing UISearchController in a TableViewController that is in a UINavigationController

I have made a UITableView Controller with a UISearchBar as the Table's header.
I have then embedded this View Controller into a UINavigationController, as the root view controller.
Now, when I tap on the Search Bar, the SearchBar seems to disappears and displays a white screen. The keyboard appears, but there is no Search Bar.
The Table View can scroll, but the search bar has simply vanished.
When I implement this UITableViewController without the Navigation Controller, it works perfectly. But something about the Navigation Controller is borking everything up.
I've had the same issue that was sometimes happening, especially with table view of small number of rows (less than 50).
It appears the searchBar is removed from the view hierarchy, precisely from the container view that is a child of the UISearchControllerView.
I've found a workaround to manually add back the searchbar as a subview of the UISearchControllerView container child. This is implemented in the delegate function (from UISearchControllerDelegate) didPresentSearchController:
func didPresentSearchController(searchController: UISearchController) {
if searchController.searchBar.superview == nil {
for searchCtrlChildView in searchController.view.subviews {
if searchCtrlChildView.frame.origin == CGPoint(x: 0, y: 0) { //Discriminate if by chance there was more than one subview
searchCtrlChildView.addSubview(searchController.searchBar)
break
}
}
}
}
I've also filed a radar to Apple on this as it is not fixed in iOS 8.4
Check the way I had my searchBar it in viewDidLoad
I have my viewController embedded in NavigationController too
My code (hope it helps) :
class myTableViewController: UITableViewController,UISearchResultsUpdating,UISearchControllerDelegate,UISearchBarDelegate
override func viewDidLoad() {
super.viewDidLoad()
self.resultSearchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
self.tableView.tableHeaderView = controller.searchBar
return controller
})()

Resources