Swift Hide Nav Bar on One Page - swift

I have an app that opens to the main scene and checks for a token to see if the user is logged in. If they are all is good and it loads. If not it redirects them to a login screen, they login and then it pushes them back to the main screen.
I'm trying to hide the nav bar just on the login page which loads if there's no token. I've found many instances of code that work, like this:
self.navigationController.navigationBar.hidden = true
that hide it however they also hide the nav bar on the first instance of the main page. How can I avoid this?
EDIT: I've tried the following and still no luck! Same result of the navbar hiding on the login screen but hidden when the user is first moved to the main scene. Any other move to the main screen shows the navbar. How is this happening??
Attempt 1:
ON LOGIN PAGE
In viewDidLoad() -> self.navigationController!.navigationBar.hidden = true
ON MAIN PAGE
In viewDidLoad() -> self.navigationController!.navigationBar.hidden = false
Attempt 2
ON LOGIN PAGE
override func viewWillAppear(animated: Bool) {
self.navigationController!.navigationBarHidden = true
}
ON MAIN PAGE
override func viewWillAppear(animated: Bool) {
self.navigationController!.navigationBarHidden = false
}
Attempt 3
ON LOGIN PAGE
override func viewWillAppear(animated: Bool) {
self.navigationController!.navigationBarHidden = true
}
ON MAIN PAGE
override func viewWillDisappear(animated: Bool) {
self.navigationController!.navigationBarHidden = false
}
Could it have something to do with the way I'm moving to the main page after the user logs in?
ON LOGIN PAGE:
let secondViewController = self.storyboard!.instantiateViewControllerWithIdentifier("FriendsTableViewController") as! UITableViewController
//go to the main page
self.navigationController!.pushViewController(secondViewController, animated: true)

in viewWillDissapear you can set self.navigationController.navigationBar.hidden to false again.

Set it to hidden in viewDidAppear. I had to use something like this in my application and it worked.
Override func viewWillAppear(){ Self.navigationController.navigationBar.hidden true
}

Try this:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
/** remove the shadow image (border) altogether from nav bar **/
for parent in self.navigationController!.navigationBar.subviews {
for childView in parent.subviews {
if(childView is UIImageView) {
childView.removeFromSuperview()
}
}
}
}

Related

How to update information on previous page of navigation controller without relaunching page?

I am making a quiz app and have three view controllers and I am also making use of a navigation controller. The controllers are: HomeController, LevelsController, PlayController.
The levels controller has 100 levels on it as buttons and all of them except level 1 are greyed out initially. As I complete levels, the other level buttons are unlocked and become clickable.
MY ISSUE:
This only works if I go back to the HomeController and press on the then navigate to the LevelsController again, it doesn't update instantly when I simply go back from the PlayController to the LevelsController.
This is my code in the levels controller:
import UIKit
class LevelsViewController: UIViewController {
var levels = [String]()
override func viewDidLoad() {
super.viewDidLoad()
for k in globalScore...99 {
// print("this is \(k)")
// print(levelButton)
levelButton[k].isEnabled = false
print("Have the levels updated??")
}
}
override func viewWillAppear(_ animated: Bool) {
for k in globalScore...99 {
levelButton[k].isEnabled = false
}
}
#IBOutlet var levelButton: [UIButton]!
#IBAction func levelSelect(_ sender: UIButton) {
self.level = sender.tag
performSegue(withIdentifier: "LevelToPlaySegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("my name is jacobson")
var vc2 = segue.destination as! PlayViewController
vc2.enteredLevel = self.level
}
}
My PlayController has a keyboard and an image that changes to a new image if the correct answer is input into a text field. I also have a score in the top right of the PlayController which is assigned to globalScore. as the global score increases, the levels page should have more levels available to the user when they go backwards from the PlayController to the LevelsController.
What you need to do is to change your logic and instead of using it on viewDidLoad, you should also add ViewDidAppear and ViewWillAppear, in order to call these method every time you open the viewController instead of doing it only the first time.
Jasc24 has answered this already but I'm writing exactly what worked for me.
I wrote this in my ViewDidLoad to make all levels except level 1 disabled:
for k in 1...99 {
levelButton[k].isEnabled = false
}
I wrote this after the ViewDidLoad to enable specific levels only:
override func viewWillAppear(_ animated: Bool) {
for k in 0...globalScore-1 {
levelButton[k].isEnabled = true
}
}

Present modal from NSWindowController without using Storyboards

I building a macOS framework that's running at the beginning of the login process and I want to show some information to the user in a window. I have an NSWindowController with a .XIB file and it's the main window for my framework.
I would like to add more presentAsSheet to another view. For that, I created an NSViewController with a .XIB to define the user interface that an I want to present in a modal but here I'm completely blocked because getting the contentViewController of the window its always nil
I'm initializing my main window like this:
func run() {
NSApp.activate(ignoringOtherApps: true)
mainWC = MainWC(windowNibName: "MainWC")
guard mainWC.window != nil else {
return
}
NSApp.runModal(for: mainWC.window!)
}
Where Im trying to present the other NSViewController"
self.window?.contentViewController?.presentAsSheet(customViewController)
In my MainWindowController I'm doing this:
#IBAction func btnAction(_ sender: Any) {
let customModal = CustomModal(windowNibName: "CustomModal")
self.window?.beginSheet(customModal.window!, completionHandler: { code in
print(message: "Clicked")
})
}
The modal never appears
You can't present the view until the window and the content view have been loaded
Either inside the window controller in windowDidLoad()
override func windowDidLoad() {
super.windowDidLoad()
// present the view
}
or even in viewDidLoad of the view controller
override func viewDidLoad() {
super.viewDidLoad()
// present the view
}

is there an easy way to logout when clicking the back nav item on a navigation controller in swift 4?

I've got a login screen that takes an email and password. I'm using firebase Auth.
The login screen is embedded in a navigation controller. From the login screen it goes to a UserDetailsController. There is a "back" nav item in the navbar that comes with the nav controller. I can't actually drag this to be an outlet.
I was wondering if there is an easy way for when the "back" is clicked and the user is returned to the login page to logout the user. The code for logout is relatively simple with firebase Auth. The issue i'm having is working out in LoginController if I returned to here from the UserDetailsController.
I've read up about using self.presentingcontroller to determine which controller i came back from but I keep getting nil. And I wasn't sure if this is the best/only option to determine from which controller I have navigated back from.
Thanks.
Looks pretty straightforward. Hopefully this code will help.
In viewDidLoad add a function like this:
override func viewDidLoad() {
super.viewDidLoad()
setupLogOut()
}
Then set up the function like this with a selector handler method like this:
fileprivate func setupLogOut() {
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(handleLogOut))
}
#objc func handleLogOut() {
do {
try Auth.auth().signOut()
// Present the login controller
let loginController = LoginController()
let navController = UINavigationController(rootViewController: loginController)
self.present(navController, animated: true, completion: nil)
} catch let signOutErr {
print("Failed to sign out:", signOutErr)
}
}
If you don't want to add method to back button. you can also use below method to logout:
override func viewWillDisappear(animated: Bool) {
// Your sign out logic here..
}
Above method get's called when you pop back to login controller.

How do you make a modal view appear outside of a controller?

I am trying to program a little game just to apply the concepts I learned in this course myself. When the game opens up, I would like for a custom modal view to tell the user how to play. Likewise, when they lose, I want to present a results page, which would be inside an if statement. I've searched all over the internet, and I can't find a way to display these views without an error. All that this video shows is how to show a display a view when a button is pressed; how do I display a custom modal view on command in code? (I am very new to Swift, so try to put it in layman's terms.) Thanks!
import UIKit
var numberValue = 0
let randomInt = getRandomNumber()
class ViewController: UIViewController {
#IBOutlet weak var buttonLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("HowToPlayView") as! HowToPlay
self.presentViewController(vc, animated: true, completion: nil)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonPressed() {
numberValue += 1
updateButtonValue(buttonLabel)
}
}
#IBAction func buttonPressed() {
numberValue += 1
updateButtonValue(buttonLabel)
}
}
That's my view controller. Getting error: Thread 1: EXC_BAD_ACCESS
My view in interface and connections
enter image description here
Ok, let's try a different approach to solve this issue. Above your ViewController you should see three different buttons like this:
Click on the first button and Ctrl + Drag to the view that you want to display and choose display modally. After that is done you should see this arrow appear:
This is called the segue from the first view to the second view and you can call this in your code to transition from one view to the next, but first we have to give our segue an identifier. You can do this by clicking on the arrow and a window should come up like this:
As you can see you will have to fill out the identifier field, and in my case I just named it "myAwesomeSegue".
Lastly, in the first ViewController run this code when you need to present the next view controller:
performSegueWithIdentifier("myAwesomeSegue", sender: nil)
Please note that if you use this method just delete the previous code you had before as this is a brand new approach (so basically delete this code):
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("HowToPlayView") as! HowToPlay
self.presentViewController(vc, animated: true, completion: nil)
Final code for the firstViewController:

How call delegate function without present controller

I have Tap Bar Controller with 2 paths. One is settingController Other one is loginController and contactListController.
When i run the program the entry pint is set tocontactListControllerand if login is false apps shownloginController`. After login value is set on true and loginController is dismiss. On bottom i have Tab Bar Controller: ContactList | Settings
When i go to settings i have a LOGOUT button, i would like to do when i tap this how to set value login on false ? i have no segue between ContactList and SettingController
This is my ContactListController
class ContactsTableViewController: UITableViewController, SettingsControllerDelegate {
let settingsController: SettingsController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("settingsController") as! SettingsController
override func viewDidLoad() {
super.viewDidLoad()
settingsController.delegate = self
}
func didLogoutSuccessfully() {
loggedIn = false
}
}
This is settings controller
protocol SettingsControllerDelegate {
func didLogoutSuccessfully()
}
class SettingsController: UITableViewController {
var delegate: SettingsControllerDelegate?
fun tapButton() {
self.delegate?.didLogoutSuccessfully() // Set login as false
}
if i added
override func viewDidLoad() {
super.viewDidLoad(
settingsController.delegate = self
presentViewController(settingsController, animated: true, completion: nil)
}
my controller setting is appear first. How can i change this value in other way?
UPDATE
in contact list i have
var loggedIn: Bool = false {
didSet {
if loggedIn == true {
self.configureView()
}
}
}
override func viewDidAppear(animated: Bool) {
if loggedIn == false {
performSegueWithIdentifier("showLogin", sender: nil)
}
//tableView.reloadData()
}
Consider either 1: using notifications (to which all interested controllers are registered as observers) to react to session state changes, 2: moving your session state to something "higher up the chain" (like in or "hanging off of" your app delegate), or 3: making a singleton session controller.
1 can be used with 2 and 3 and either 2 or 3 make accessing the current state from anywhere in your app easier. I'd go with a mix of 1 and 3 myself.
This approach in general relieves you from having to walk and inspect the controller hierarchy to find and set the same thig on all other controllers (which is icky because it's so tightly coupled; changing the hierarchy and/or reusing VCs elsewhere would probably break things).
You can pass data between the tabs using UITabViewControllers.viewControllers method which returns array of the view controllers in the tab
//in SettingsVC
func viewWillDisapear(){
//assuming its in the second index of tabBar
let contactVC = self.tabBarController.viewControllers[1] as ContactsTableViewController
contactVC.delegate = self
contactVC.loggedIn = true //or false as you wish
super.viewWillDisapear()
}