navigation controller custom search bar not disappearing? - ios

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()
}

Related

Add child view controller to UITabBarController issue

I'm trying to add an UIViewController as child view controller to the tab bar controller. See code below:
guard let vc = self.storyboard?.instantiateViewController(withIdentifier: "MyAlertViewController") as? MyAlertViewController else
{
return
}
let base: UITabBarController = tabBarController!
base.addChildViewController(vc)
vc.view.frame = base.view.bounds
base.view.addSubview(vc.view)
vc.didMove(toParentViewController: base)
It works, but there is an issue that I'm unable to solve: MyAlertViewController is added to tab bar controller's viewControllers array, and sometimes it is even shown as a tab bar item. Is there a way to solve this? Thanks.

Swift and Xcode. All UIViewControllers become black when added to TabBarController

I'm trying to create UITabBarController programmatically, adding multiple NavigationControllers to it. When UITabBarController contains one NavigationController - everything works as expected (see image)
But when i add multiple NavigationControllers to UITabBarController each screen becomes black (see another image )
The same black screen is shown when switching between tabs 1, 2, 3, 4 and 5.
Here's the code how UITabBarController is created
class TabBarViewController : UITabBarController{
override func viewDidLoad() {
super.viewDidLoad()
let controllers = [HistoryViewController.self, StatsViewController.self, DashboardViewController.self, ExpenseManagerViewController.self, ProfileViewController.self]
var navControllers: [UINavigationController] = []
controllers.forEach{ ctrl in
navControllers.append(getController(from: ctrl))
}
tabBar.tintColor = Color.green
viewControllers = navControllers
}
private func getController<TType: UIViewController>(from type: TType.Type) -> UINavigationController{
let ctrl = TType()
let navCtrl = UINavigationController(rootViewController: ctrl)
let ctrlName = String.init(describing: type.self).replacingOccurrences(of: "ViewController", with: String.empty)
navCtrl.tabBarItem.title = ctrlName
navCtrl.tabBarItem.image = UIImage(named: ctrlName)
navCtrl.navigationBar.topItem?.title = ctrlName
return navCtrl
}
}
Those UIViewControllers are created using "add Cocoa Touch Class" option and have assigned *.xib files with some minimum design (see one more image)
Any help regarding why all screens become black when multiple (2 and more) NavigationControllers added to TabBarController would be highly appreciated.
Thanks
Clearly you forget how to init the UIViewControllers with xib file:
private func getController<TType: UIViewController>(from type: TType.Type) -> UINavigationController{
let ctrl = TType(nibName: String.init(describing: type.self), bundle: nil)
let navCtrl = UINavigationController(rootViewController: ctrl)
First if you come from any screen then dont insert navigationbar in between that viewcontroller and tabbarcontroller and when you jump to tabbarcontroller set as rootview controller and any tab you want to open than place navigation controller in between. means dont open tabbar controller with navigationbar heirarchy but when u want to open controller with tabs then place navigation controller in between.

Switch tab bar view in subview programmatically (custom tab bar controller)

Because I want to redesign the tab bar UI, I wrote a custom tab bar controller according to https://github.com/codepath/ios_guides/wiki/Creating-a-Custom-Tab-Bar
In TabBarViewController's viewDidLoad(), define several subviews corresponding to each tab bar
homeViewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
...
viewControllers = [homeViewController, searchViewController, accountViewController, trendingViewController]
and the main method when tapping tab
#IBAction func didPressTab(_ sender: UIButton) {
let previousIndex = selectedIndex
selectedIndex = sender.tag
tabButtons[previousIndex!].isSelected = false
let previousVC = viewControllers[previousIndex!]
// remove previous VC
previousVC.willMove(toParentViewController: nil)
previousVC.view.removeFromSuperview()
previousVC.removeFromParentViewController()
// set current VC
sender.isSelected = true
let vc = viewControllers[selectedIndex]
addChildViewController(vc)
// Adjust the size to match content view
vc.view.frame = contentView.bounds
contentView.addSubview(vc.view)
vc.didMove(toParentViewController: self)
}
I could set a default tab bar index selectedIndex when the tab bar view is loaded. However, how can I switch to next tab bar in homeViewController (without tapping tab bar buttons)?
This doesn't work in homeViewController
TabBarViewController().tabButtons[2].isSelected = true TabBarViewController().didPressTab(TabBarViewController().tabButtons[2])
I'm not sure how to get the running tab controller, set the selectedIndex, and update subview in the subview controllers.
All you need to do is to call tabBar.setSelectedViewController: and pass the view controller.
If you only know the tab index, you call tabBar.viewControllers[index] and get the view controller.
I finally use Delegate to solve.
In SubViewController add protocol
protocol SubViewControllerDelegate {
func transferToView(index: Int)
}
and declare this in the class
var delegate: SubViewControllerDelegate?
In TabBarViewController set to conform SubViewControllerDelegate
Implement the method
func transferToView(index: Int) {
tabButtons[index].isSelected = true
didPressTab(tabButtons[index])
}
Set delegate
subViewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
let subVC = subViewController as! SubViewController
subVC.delegate = self

How to remove NavigationController

In my app I am using a NavigationController to display a SlideView by using following code
func addChildSidePanelController(sidePanelController: SlideViewController) {
sidePanelController.delegate = centerViewController
let navigationController: UINavigationController = UINavigationController(rootViewController: sidePanelController)
view.insertSubview(navigationController.view, atIndex: 0)
addChildViewController(navigationController)
navigationController.didMoveToParentViewController(self)
}
So the centerViewController is my mainViewController. After the usage of this side panel, I need to remove it from my MainView. Currently I am using code
self.leftViewController?.view.removeFromSuperview()
self.leftViewController = nil;
The view inside the NavigationController is removed by this code, but the navigation bar and other container layers are still there.
How to remove whole navigation controller?

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
})

Resources