Navigation Bar Hidden on Segue/Push (Swift) - ios

I used the following code to redirect from a child to the parent (except I had to load different data on the parent--think of it as a chat app with a button to see your profile and you can click on some other friend of yours to redirect to a different chat i.e. a different dataset). I initially used
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "parent") as! UIViewController
self.navigationController?.pushViewController(popOverVC, animated: true)
But that allowed me to go back to previous chat by swiping left (I tried disabling that by hiding back button, using
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
and it didn't disable the swipe back feature either (I used it in ViewDidLoad, ViewWillAppear, ViewWillLayoutSubViews and still it didn't work; I could still swipe back to previous chat). So I tried using the following and while it worked, my nav bar would disappear.
navigationController?.setNavigationBarHidden(false, animated: true)
worked when I used the pushViewController (but it would still let me swipe back) and it doesn't work when I use the root VC (but it disables the swipe back)
Here is the rootVC method I'm talking about:
let window = UIApplication.shared.windows[0] as UIWindow
popOverVC.navigationController?.setNavigationBarHidden(false, animated: true)
window.rootViewController = popOverVC

As most of the iOS Users go back by swiping and less by pressing the back button.
For it would be more reasonable to use a modal segue instead of a push segue which is not that big of a transfer. You can just disable back button.
self.navigationController?.navigationItem.backBarButtonItem?.isEnabled = false

Related

Page views not correctly sized after segue

I recently updated my XCode to version 11.0. Ever since the update segues on an old project have been behaving weirdly. When I segue modally to a new page the page does not fill the entire screen and seemingly hovers instead.
Here is a picture of the view:
https://imgur.com/dAxEr4q
I would like for the pages to take up the full length of the device screen as they did prior to the upgrade.
Thanks in advance for any assistance.
This has to do with the new default modal presentation style in iOS 13.
To set the prior behavior, you need to change the presentation style to full screen.
You can do this both in storyboard by editing your segue's Presentation attribute and setting it from Automatic to Full Screen:
Alternatively, if you are presenting your View Controller programmatically, you can set your View Controllers modalPresentationStyle before presenting it, like so:
let detailController = /* your View Controller */
detailController.modalPresentationStyle = .overFullScreen
present(detailController, animated: true, completion: nil)
So the solution turned out to be more obvious than I realized. If you click on the segue symbol on the storyboard some options are displayed in the side bar.
Selecting presentation -> full screen from the drop down fixed my issue.
Adding a screenshot for clarity: https://imgur.com/BRCbx5k
Hope this helps anyone else having segue problems :)
You can programmatically present the controller like in below code :
let vc = secondStoryBoard.instantiateViewController(withIdentifier: "SearchNavVC")
vc.modalPresentationStyle = .fullScreen
vc.modalTransitionStyle = .crossDissolve
self.present(vc, animated: true, completion: nil)

How is this settings popup created? [duplicate]

This question already has answers here:
Present a popover from an arbitrary anchor point in Swift
(3 answers)
Closed 4 years ago.
I really like the way the settings are shown on the Books app and am trying to figure out how replicated it.
Screenshot of Books app with settings shown
Is this an .actionsheet that is somehow moved to show up under the Settings image or a container view that shows up on tap or something else? I'm still at level noob with a basic app and would like to implement this.
It is iOS default presentation style for controllers. It's called UIPopOverPresentationController. Here's a good article on presentation controllers. After that you might want to create two to three cells for your options in a UITableView and add that as controller for the popover from your storyboard.
You can also change the popover arrow pointing location and direction which you might need when you want to support your app for iPad as well. :)
#IBAction func actionWasTapped(sender: UIBarButtonItem) {
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "PopOverVC")
vc.modalPresentationStyle = .popover
let popover: UIPopoverPresentationController = vc.popoverPresentationController!
popover.barButtonItem = sender
present(vc, animated: true, completion: nil)
}
This can done with a-lot of way , you can just create by
UIView work as background with custom subview (PopOverMenu) done with UIBezierPath to draw this arrow with corner radius view
upon this pop over you can create MultiSection tableview or collection View or any
Background is add as SubView to UIApplication.sharedApplication().keyWindow?.addSubview(background)
Background have tab gesture to dismiss when tab on background
some closure to bring back data that user select it

Container View Controller disappears when Child View Controller presents a Modal View Controller iOS Swift

I'm new to the iOS swift scene and i was hoping you would be able to help me find a solution or send me on an alternative route to achieving this.
Here is the diagram to my Application Interface Structure
So, i have the ContainerVC which has a UIScrollView, and that UIScrollView has a the four ChildVCs inside. My problem is when i present the ModalVC from one of the ChildVCs, the ContainerVC, which has the UIScrollView
and the application's background disappears from the screen completely and the background of the app becomes black. I believe that happens because iOS thinks that the ContainerVC is no longer being used so it removes it from the hierarchy when the modal is presented on top of the ChildVC.
I wanted to be able to have the ContainerVC, which provides a background for the app and the UIScrollView where the ChildVC are embedded, visible at all times even when a ChildVC presents the ModalVC modally. Before the ModalVC is presented, the ContainerVC can be seen behind the ChildVC around the edges (modal ahah) of the screen and everything is fine, but that changes when i trigger a tap event and i present the modal. Here is the before and after:
Before Tap Event >>>
After Tap Event & ModalVC appears
You can see that the purple background disappeared now that the ModalVC is presented and though you cant see it, I'm not able to scroll side ways anymore because the UIScrollView isn't there either.
How can i present the ModalVC from the ChildVC without losing the ContainerVC and its UIScrollView inside? i.e. from disappearing and staying the the view hierarchy
Here is the code is use to present the ModalVC from a given ChildVC.
func didTapCell(origin: String) {
let modalVC = storyboard?.instantiateViewController(withIdentifier: "overlayModal") as! OverlayModalViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = self // i think this self has something to do with the background disappearing
modalVC.modalPresentationStyle = .overCurrentContext
self.present(modalVC, animated: true, completion: nil)
}
I have been looking for a solution for a while now but i can't seem the figure it out. I would be great if you could help work this out or help find a way around it and achieving the same. Please help me out.
Thank you in advance. Please let me know if there's anything i can do to clarify anything.

Is it possible to prepare/reset a scene before it is shown / before viewDidAppear / viewDidLoad?

I am having a viewController with a couple of animated buttons, when the user presses a button the background is blurred (animation) and a menu to choose a couple of things (which all go to a new viewController) is presented.
So basically there is a scene, the user opens the menu, the scene is blurred except for the menu and the user presses a button and another viewController is shown programmatically with a crossDissolve. This is how I show the new controller:
let storyboard = UIStoryboard.init(name: "Timer", bundle: nil)
let vc = storyboard.instantiateInitialViewController()!
vc.modalTransitionStyle = .crossDissolve
present(vc, animated: true, completion: nil)
So far so good, but I am not able to reset the original scene (basically to just remove the blur and reset the animated buttons). I have a function in it called setupScene() which prepares everything for the app start (some buttons are hidden, the blur has an alpha of 0, etc....).
I just dismiss the new viewController like this:
dismiss(animated: true, completion: nil)
And than the original scene with it's last state (blurred etc.) is shown again.
So when the new viewController is presented I would like to reset everything in the original viewController in the background, so that when the new viewController is dismissed the old scene is already reset, but this doesn't work. I tried to move the setupScene() function in viewDidAppear, but either in viewDidAppear or viewDidLoad first the new viewController is dismissed showing the original viewController in it's last state with the blur again and then the setupScene() runs to reset everything (which obviously works fine).
Is there a way to reset everything in the background while the new viewController is shown or while the crossDissolve is running?
This sounds like a good case for viewWillAppear. This is a lifecycle method that is called when the visibility of a view controller's views change. viewDidLoad is only called once.
There are several solutions to this, depending on how fancy you want to get.
Based on what you describe I think the first thing to try is to take advantage of that completion parameter in dismiss(animated:completion:)
It's a callback to your code once the dismiss is completed. This will allow you to reverse your animation.
The callback takes no parameters.
So, if your setupScene() method does what it says,
dismiss(animated: true, completion: {
setupScene()
})
should do it.

Edit button not displayed in UITabBarController's MoreNavigationController

A UITabBarController is being pushed onto the stack:
let presenter = presentingViewController as! UINavigationController
let tabvc = UITabBarController()
tabvc.viewControllers = vcs
tabvc.customizableViewControllers = vcs
presenter.pushViewController(tabvc, animated: true)
Once presented the more tab button correctly shows, but the edit button to rearrange the tab bars does not. According to the docs on the MoreNavigationController:
The interface for the standard More item includes an Edit button that
allows the user to reconfigure the tab bar. By default, the user is
allowed to rearrange all items on the tab bar. If you do not want the
user to modify some items, though, you can remove the appropriate view
controllers from the array in the customizableViewControllers
property.
My guess is that the tab bar is not happy being in a navigation controller. Any ideas on bringing the edit button back?
You can have both a UINavigationController and a UITabBarController ; using Storyboard helps understand the issue better, any of these solutions will work:
Start out with a UITabBarController as initial view controller
Use presentViewController instead of pushViewController
Use a modal Storyboard segue to perform a modal presentation
Swap out the rootViewController dynamically
Initial View Controller Design
When the Tab Bar Controller is initial View Controller, the Edit button is displayed normally.
Pushed Design
Another Navigation Controller is initial View Controller, using one of 5 adaptive Action Segue:
Show
Custom
-> No Edit button, since it is in direct conflict with the parent UITableViewController.
Show Detail
Present Modally
Popover Presentation
-> Edit button displayed as expected.
Code
1. Program Modal
Using the exact code presented in the question, change the last line:
let presenter = presentingViewController as! UINavigationController
let tabvc = UITabBarController()
tabvc.viewControllers = vcs
tabvc.customizableViewControllers = vcs
presenter.presentViewController(tabvc, animated: true, completion: nil)
2. Storyboard Modal
keeping with the Storyboard theme, create a segue of the correct type, assign an identifier (i.e. presentModallySegue) and the 5 lines above become this single line:
self.performSegueWithIdentifier("presentModallySegue", sender: self)
3. root Swap
A more drastic solution involves swapping out the root view controller at the window level:
let tabvc = UITabBarController()
tabvc.viewControllers = vcs
tabvc.customizableViewControllers = vcs
self.view.window!.rootViewController = tabvc
Conclusion
Either change your design to adopt the Tab Bar Controller as the initial View Controller, or present the Tab Bar Controller modally.
The reason is that navigation bar of your presenter overlaps with the navigation bar of More section.
If you don't show the navigation bar for you navigation controller, you will be able to see the Edit button again when you tap on the More tab.

Resources