I have weird situation and have no clue how to debug it. I load three viewControllers in navigation controller. When Im navigating back from there second and first ViewController doesn't display anything just white screen I added print methods everywhere in lifecycle methods and it seems that it loads views but anyway they not visible. What could be the problem?
Yep It's weird, There maybe some code which do something with your view on such events like:
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// remove some subviews or change constraints.
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// remove some subviews or change constraints.
}
Please send us a code of the view controller which has the problems and code how exactly you show the controller.
Related
When I scroll on my UITableView, an empty header appears at the top of the view that prevents the user to see some information properly as you can see in the following screenshot:
How can I remove this?
It is actually a UINavigationBar that you're seeing. Try this in your UIViewController to hide the navigation bar:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
If the navigation bar is used in previous view controllers in your navigation stack, make sure to make it visible there again.
I've noticed that, when using the long-press back button feature in iOS 14, any properties relating to UINavigationController's view controller stack (.viewControllers, .topViewController, etc.) seem incorrect. Specifically, the order is reversed.
Regarding the .viewControllers property, Apple's docs state:
The root view controller is at index 0 in the array, the back view controller is at index n-2, and the top controller is at index n-1, where n is the number of items in the array.
If I've got three view controllers in a nav stack like as follows
[ViewController01, ViewController02, ViewController03] and print out the .viewControllers property in viewWillAppear, I get the expected output of:
[ViewController01]
[ViewController01, ViewController02]
[ViewController01, ViewController02, ViewController03]
If I tap the back button from ViewController03, I get the expected output from viewWillAppear in ViewController02:
[ViewController01, ViewController02]
However, if I set everything up again so I've got [ViewController01, ViewController02, ViewController03] and then use the long-press back button feature to jump back to ViewController01, I get the unexpected output of:
[ViewController03, ViewController01]
From viewWillAppear in ViewController01.
I'm not expecting this because ViewController03 isn't, and never was, the root view controller of the navigation stack. As per the docs, I'm expecting:
[ViewController01, ViewController03]
Could someone please let me know if this is expected behaviour or if I've overlooked something super-obvious?
Thank you!
I've reproduced this in a small sample app based on a "single view controller" project. Just embed the initial view controller in a nav stack and include the following:
class StubViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("\(self) will appear. Current nav stack follows:")
print("\(self.navigationController?.viewControllers ?? [])")
}
}
class ViewController: StubViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.pushViewController(TestViewController01(), animated: true)
}
}
class TestViewController01: StubViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.pushViewController(TestViewController02(), animated: true)
}
}
class TestViewController02: StubViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.pushViewController(TestViewController03(), animated: true)
}
}
class TestViewController03: StubViewController {
}
(I'm aware the above is very horrible)
Basically, what's happening here is that you have accidentally looked inside the sausage factory and you've seen how the sausage is made. And it isn't pretty...!
The workaround is: don't do that. Give the view controllers stack a chance to settle down before you look at it:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {
print("\(self) will appear. Current nav stack follows:")
print("\(self.navigationController?.viewControllers ?? [])")
}
}
Even more simple: just move the code to viewDidAppear.
i'm stuck with this too, but what i've found is navigation controller changed the viewControllers stack because of animation to handle what controller will goes to another in back operation
for example if stack is [vc1, vc2, vc3, vc4] and you are in vc4 and if you call
navigationController.popToRootViewController(animated: true)
stack will be [vc4, vc1] in willShow delegate method.
the only way i found is to set animation to false
navigationController.popToRootViewController(animated: false)
to keep the stack as what it really is
I'am working on an app, which is embedded in a UINavigationController. I like Storyboard, so I am looking for a solution that could be done in Storyboard. If that's not possible, I am doing it programmatically.
I want different settings for the top- and toolbar (hide/ show). See the image below.
Now look at situation two. I want the third ViewController to have no topbar. But if I set it to "none", four and five have no topbar as well. See image:
What I want is only the third controller not to have a topbar.
How is this possible in Storyboard?
Thanks!
Niels
In your viewWillAppear() of your third ViewController add this simple line of code -
self.navigationController?.isNavigationBarHidden = true
From Storyboard -
Click on that specific ViewController where you don't want to show the bar then go to Attributes inspector. There is a drop down labeled Top Bar change this drop down to none
And for the smooth animation -
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Hide the navigation bar on the this view controller
self.navigationController?.setNavigationBarHidden(true, animated: animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Show the navigation bar on other view controllers
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
I thought showing a screenshot would help understand the issue a bit better.
So the context is the following:
I'm in a navigation controller, on the settings screen of the app (which has a navigation item) and when we tap on the back button, we go back to the main screen of the app (for which I've hidden the navigation bar in the viewWillAppear of the main screen because I'm building a custom header view myself).
At soon as I tap on the back button, the navigation bar disappears immediately and I see a black rectangle appears instead until the animation to display the main screen is completed.
Do you know how I can avoid having this black rectangle appear?
Hope the questions makes sense.
Screenshots
Here is the initial settings screen:
When we tape on the back button, this happens... help :D
I know this piece of code is most likely responsible for the error, but I absolutely need to have the navigationBar hidden on the previous screen.
override func viewWillAppear(_ animated: Bool) {
navigationController?.isNavigationBarHidden = true
}
Have you tried the animated method of hiding the navigation bar setNavigationBarHidden(_ hidden: Bool, animated: Bool)?
For Swift3.0
Add below code in First ViewController
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
Add below code in Second ViewController
func backButtonPressed() {
navigationController?.setNavigationBarHidden(false, animated: false)
navigationController?.popViewController(animated: true)
}
Add below code in Second ViewController
the color can corresponding your custom
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.view.backgroundColor = UIColor.white
}
I got my table view on top of a map view. I want to show to user that the tableView is scrollable. Here is my previos thread: Swift - How to attach bar to the top of table view?
I tried using
self.tableView.flashScrollIndicators()
in my ViewDidLoad() method but this doesn't change anything, the table view looks exactly the same as before. I read suggestion that it might be caused by reloading tableView and filling it with data, whilst created tableView is empty. Nonetheless I tried pasting the flashScrollIndicators() method in other project where table is created with cells immediately - again no significant difference.
Am I doing something wrong or using the method in wrong place?
If anyone is still fighting with this problem here is my working solution - works on iOS 11. In my case flashScrollIndicators() did not work on first invocation of viewDidAppear(animated:). Invoking flashScrollIndicators() with a delay will do the trick.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.asyncAfter(deadline: (.now() + .milliseconds(500))) {
self.collectionView.flashScrollIndicators()
}
}
You're using the method in the wrong place. In viewDidLoad, the view has just finished loading. It hasn't yet been displayed. A safe alternative would be to move the call into your view controller's viewDidAppear: method to make sure that you don't attempt to flash the scroll indicator until the view is already on screen.
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.tableView.flashScrollIndicators()
}
Swift 4
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.tableView.flashScrollIndicators()
}