bottom tabbar disappears and leave black when pushed from UITableViewController to UIViewController - swift

In my use case, I want to hide the bottom tabbar when navigating away from UITabbarController.
I was using
let vc = storyboard?.instantiateViewController(withIdentifier: tableData[indexPath.row]["vcIdentifier"]!)
self.hidesBottomBarWhenPushed = true
self.show(vc!, sender: self)
It sorta works, because the pushed view controller doesn't have tabbar at bottom. However, as soon as I click on navigate, the bottom tabbar of the "sender" view controller vanishes and leaves black area.
Please let me know if you need to have more information about anything. Thanks a lot in advance!

If the pushed view controller doesn't have a tab bar at the bottom, you can add this lifecycle of view controller codes.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tabBarController?.tabBar.isHidden = true
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
tabBarController?.tabBar.isHidden = false
}

you can use segue if you want to hide tabbar while going to the next screen. it will automatically hide it.

Related

Presenting UISearchController programmatically

I am presenting a UISearchController programmatically, without adding it to the navigationItem. The Calendar app does something similar.
Without a presentation context, the search bar appears correctly, but persists after pushing another view controller.
This is expected, so we need to set definesPresentationContext on the list view controller... But that causes the search bar to render incorrectly.
Here's the code for context:
private lazy var searchController: UISearchController! = {
let searchController = UISearchController(searchResultsController: nil)
searchController.obscuresBackgroundDuringPresentation = false
// If this is set to true, the search bar animates correctly, but that's
// not the effect I'm after. See the next video.
searchController.hidesNavigationBarDuringPresentation = false
return searchController
}()
override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
searchButton.rx.tap.subscribe(onNext: { [unowned self] in
present(searchController, animated: true)
}).disposed(by: disposeBag)
}
Setting hidesNavigationBarDuringPresentation kind of fixes it, but we lose the tab bar, and the whole thing just looks bad.
I tried this solution (Unable to present a UISearchController), but it didn't help.
Any suggestions?
UPDATE: The issue is, more specifically, that the search bar appears behind the translucent navigation bar. Making the nav bar solid ( navigationController?.navigationBar.isTranslucent = false) makes the search bar appear under the nav bar.
I have the same problem not been able to solve this either. It seems like the problem is that either
a) the searchcontroller is presented at the very top of the viewcontroller stack, even above the navigation controller, so that it stays active into the next viewcontroller push. or,
b) the searchcontroller is presented underneath the navigationcontroller so that it remains covered by the navigation bar
One idea: don't embed the viewcontroller which is presenting the searchcontroller in a navigation controller. instead, just create a UIView which looks like a navigation bar a the top. would this be an inappropriate solution?
I haven't found a solution to the original problem, but I found a workaround: intercept navigation events, and manually dismiss the search controller.
override func viewDidLoad() {
...
// This makes the search bar appear behind the nav bar
// definesPresentationContext = true
navigationController?.delegate = self
}
extension JobListViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController, animated: Bool) {
// `animated` is false because, for some reason, the dismissal animation doesn't start
// until the transition has completed, when we've already arrived at the new controller
searchController.dismiss(animated: false, completion: nil)
}
}
I found that presenting the search controller over the navigation bar can be achieved by calling present(_:animated:completion:) on the navigation controller itself rather than the navigation controller's child.
So in your view controller you can do
navigationController?.present(searchController, animated: true)
And this will behave like the search button in the Apple's Calendar app.
Update
Regarding dismissing the search controller before pushing a new controller to the navigation stack, you can do this manually depending on how the push is done.
All the bellow will animate dismissing the search controller before the push happens. Note that I disable user interaction until the dismiss animation completes to prevent pushing the same view controller multiple times.
UIStoryboardSegue
Add this override to your view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if navigationController?.presentedViewController == searchController {
view.isUserInteractionEnabled = false
searchController.dismiss(animated: true) {
self.view.isUserInteractionEnabled = true
}
}
}
IBAction (Programmatically)
Just dismiss the search controller before pushing view controllers to the navigation stack:
#IBAction func showSecondTapped(_ sender: UIButton) {
// Dismiss the search controller first.
view.isUserInteractionEnabled = false
searchController.dismiss(animated: true) {
self.view.isUserInteractionEnabled = true
}
// Build and push the detail view controller.
if let secondViewController = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") {
navigationController?.pushViewController(secondViewController, animated: true)
}
}
Handling pop gesture
If the view controller that is presenting the search controller is not the root of your navigation controller, the user might be able to use the interactive pop gesture, which will also keep the search controller presented after the pop. You can handle this by making your view controller the delegate for the search controller, conform to UISearchControllerDelegate and adding the following code:
extension ViewController: UISearchControllerDelegate {
func willPresentSearchController(_ searchController: UISearchController) {
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}
func willDismissSearchController(_ searchController: UISearchController) {
navigationController?.interactivePopGestureRecognizer?.isEnabled = true
}
}

small navigation title is showing for few seconds

I have set large title in viewWillAppear()
self.navigationItem.largeTitleDisplayMode = .always
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.title = "Reports"
But still when I redirect to next VC and come back I can see navigation Title in small size for a while and then I see large title, anybody know why and how to fix it?
If you want the next VC to have largeTitleDisplayMode false, you could try to set it in viewWillDisappear() of the current VC, like this:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.navigationBar.prefersLargeTitles = false
}
You should set this in the viewDidLoad of your view controller, not the viewWillAppear. It's the first part in the view lifecycle and where this work should be done

UINavigationController transition issue

This is a Apple simple guide about Table Search with UISearchController, and I have downloaded the demo project and it is working well.
https://developer.apple.com/library/content/samplecode/TableSearch_UISearchController/Introduction/Intro.html
I want to have transparent navigation bar on product detail view (DetailViewController.swift). After changing some behaviors I have transition issue when going back from product detail to device list with swipe gesture(Video link below).
https://www.dropbox.com/s/denqomhhxasxv58/issue.mov?dl=0
For transparent navigation bar I have added this lines on DetailViewController
viewWillAppear method
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// ...
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
}
In MainTableViewController.swift I have added this code to make navigationBar default style.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
}
Also I made changes on MainTableViewController viewDidLoad method and sets this properties to true.
navigationItem.hidesSearchBarWhenScrolling = true
searchController.dimsBackgroundDuringPresentation = true
So my problem is to fix that issue. Anyone can help me?
Update:
Swipe transition from product detail to device list
Search controller active state when product detail not opened
Search controller active state after product detail opened

Nav BarItem Returning To Previous View

In the below figure, I have a "Back" button in the nav bar which I would want for it to close the Barcode Scanner tab and bring me to to the view I was prior to hitting the "Back button. How would that be possible?
Your request is improper UI. Tabs should not contain back button for going to previous tab, and I really hope that 'Close' the tab doesn't mean you want to remove it.
Other than that you can change active tab UITabBar.setSelectedItem. But really in your case don't do it.
View controllers that you load are all stacked in order of you viewing them. To go back to your previous view simply dismiss the last view controller. You can use this code:
#IBAction func backButtonPressed(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
Hopefully this should do the trick.
you can override back button in ViewDidLoad like :
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(self.back(_:)))
}
func back(_ sender: AnyObject) {
//if you want to go to previous view use this code
self.navigationController?.popViewController(animated: true)
//if you want to go to a tab bar view use this code
//index of your tab bar
tabBarController?.selectedIndex = 1
}

Swift, Navigation bar should not be shown on the login screen

I have initialized Navigation controller from the root controller (viewController), and wrote down the code to hide it initially
self.navigationController?.setNavigationBarHidden(navigationController?.navigationBarHidden == false, animated: true)
But when i go to next screen and click on the back button , i can see my navigation bar on my Login screen.
Ideally we can't show the navigationbar on login screen, What should i do to avoid this?
Login Screen ViewDidload write following line
navigationController?.setNavigationBarHidden(true, animated: true)
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: true)
}