how to open 'LGSideMenuController' side menu open from all viewcontroller? - swift

I used 'LGSideMenuController' in my project. but it cannot open from my all viewcontroller. I want to open sidemenu in all my viewcontroller in my project. But right now I am able to open it from my 'HomeViewcontroller' and only for one time.
In my AppDelegete.swift file I make function and it called in otpviewcontroller.
func createSideMenu(){
let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
let rootviewcontroller = storyBoard.instantiateViewController(withIdentifier: "HomeVC") as! HomeVC
let navigation = UINavigationController.init(rootViewController: rootviewcontroller)
let sideMenuVC = storyBoard.instantiateViewController(withIdentifier: "SideMenuVC") as! SideMenuVC
let sideMenuController = LGSideMenuController(rootViewController: navigation,
leftViewController: sideMenuVC,
rightViewController: nil)
sideMenuController.leftViewWidth = 280.0
sideMenuController.leftViewPresentationStyle = .scaleFromBig
self.window?.rootViewController = sideMenuController
self.window?.makeKeyAndVisible()
}
In my 'Homeviewcontroller' and otherviewcontroller I open sidemenu like this.
#IBAction func sideMenuAction(_ sender: UIBarButtonItem) {
self.sideMenuController?.showLeftView(animated: true, completionHandler: nil)
}
It open in only HomeViewcontroller but I want to open it in all Viewcontroller of my project. I am new in swift. Please help me. Thank you.

You can use the same method to open "LGSideMenuController" as you did in "HomeViewcontroller".
Suppose in another viewcontroller, you want to open "LGSideMenuController" on click of button event then code will look like
#IBAction func openSideMenu(_ sender: Any) {
self.sideMenuController?.showLeftView(animated: true, completionHandler: nil)
}
Edit Answer
I checked your code and found that you are trying to present another viewcontroller screen over "LGSideMenuController" instead of using push transition.
Please change your code in SideMenuVC controller as below
#IBAction func eventsAction(_ sender: Any) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "EventsVC") as! EventsVC
//let navigationController = UINavigationController(rootViewController: vc)
//self.present(navigationController, animated: true, completion: nil)
self.sideMenuController?.hideLeftViewAnimated()
self.sideMenuController?.rootViewController?.show(vc, sender: self)
}
In the above code, i hide the sidemenu first and then push "EventsVC" view controller in sideMenuController. Please apply the same code on other button actions.
Hope it helps.

Related

Sign Out button to Present Login View Controller - Swift 5

Hi I'm kind of new to Swift and I can't figure this out. I am trying to create a sign out button that would take user to the login page. I used the following two methods but the first one doesn't do anything and the second one is throwing Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value and it refers to the code with the customButton:
//this one doesn't do anything
#objc func SignOut(){
let vc = self.storyboard?.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
let appDelegate = UIApplication.shared.delegate
appDelegate?.window??.rootViewController = vc
}
//this one is throwing an error
let vc = CustomViewController()
self.present(vc, animated: true, completion: nil)
//the Fatal error refers to this code
override func viewDidLoad() {
super.viewDidLoad()
self.customButton.addTarget(self, action: #selector(customButtonPressed), for: .touchUpInside)
}
Also, I was wondering if AppDelegate is the right approach or if I should use SceneDelegate. Any help would be greatly appreciated.
Try to do this
#objc func SignOut(){
let vc = self.storyboard?.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
self.view.window?.rootViewController = vc
}
let vc = self.storyboard?.instantiateViewController(identifier: "LoginViewController") as! LoginViewController
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true, completion: nil)
Please make sure the identifier is matching the one inside storyboard for this viewController

Prevent ViewController from stacking in the background when created with present

I use this code to open a new ViewController:
// Get a random next post
#IBAction func buttonNextPostTapped(_ sender: UIButton) {
let postNumber = Int.random(in: 0 ..< postIds.count)
let postId = postIds[postNumber]
PostApi.shared.getPost(postId: postId) { (post) in
let storyBoard : UIStoryboard = UIStoryboard(name: "MainApplication", bundle: nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "PostsViewController") as! PostsViewController
nextViewController.post = post
nextViewController.isFromRandom = true
self.present(nextViewController, animated: true, completion: {})
}
}
This code will open the same ViewController with different data. It works, however, the "old" ViewControllers will stack in the background. So if I open 10 new ViewControllers, I have 10 VC in the background.
How can I present a new ViewController, and dismiss the "old" one?
Using setViewControllers function from UINavigationController is the best way.
func setViewControllers(_ viewControllers: [UIViewController], animated: Bool)
And you can remove whichever controller you want to from stack like
if var navigationControllersArray:Array = (self.navigationController?.viewControllers) {
navigationControllersArray.remove(at: navigationControllersArray.count-2)
self.navigationController?.viewControllers = navigationControllersArray
}

Swift - How switch between storyboards with back button?

I'm in a storyboard and I need to go to another storyboard by tapping a button. Well, this I've already done, but I need to go back to previous storyboard. Here is my code:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
}
By tapping a button on my UITableViewCell (where I have a protocol), this function (goContact) is called and I switch to another storyboard (FAQ). But, how can I go back to main.storyboard?
I've already tried do this too:
func goContact() {
let storyboard = UIStoryboard(name: "FAQ", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ContactViewController")
self.navigationController?.show(vc, sender: nil)
// self.navigationController?.pushViewController(vc, animated: true)
// self.present(vc, animated: true, completion: nil)
}
Use only storyboard property , it references to Main storyboard of the app or you can write it like let storyboard = UIStoryboard(name: "Main", bundle: nil)
To go back after push do
self.navigationController?.popViewController(animated: true)
You should push your new view controller onto the navigation controller using push, like in your commented-out code. That will cause the new view controller to have a back button, which will pop it for you without needing any extra code.

Google sign out and return to login page

I want to click the Sign Out button on the ListViewController to sign out the user, and return to the SignInViewController, like below picture.
In ListViewController for the SignOut button:
#IBAction func didTapSignOut(_ sender: Any) {
//Sign Out
GIDSignIn.sharedInstance().signOut()
//Go to the `SignInViewController`
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desVC = mainStoryboard.instantiateViewController(withIdentifier: "SignInViewController") as! SignInViewController
self.navigationController?.pushViewController(desVC, animated: true)
}
When back to the SignInViewController, there's a back button, which is directed back to the ListViewController on it. It seems like the app still has the cache of the user's data so the user doesn't actually sign out.
But what I want is to go back to the app's initial state that the user has to sign in again.
My Storyboard:
How I move from SignInViewController to ListViewController: in AppDelegate
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
if let error = error {
print("\(error.localizedDescription)")
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabbarVC = storyboard.instantiateViewController(withIdentifier: "TabbarIdentifier") as! UITabBarController
self.window?.rootViewController?.present(tabbarVC, animated: false, completion: nil)
}
}
Solution I've tried:
var window: UIWindow?
#IBAction func didTapSignOut(_ sender: Any) {
GIDSignIn.sharedInstance().signOut()
let desVC: UIViewController = SignInViewController()
if let window = self.window{
window.rootViewController = desVC
}
self.navigationController?.popToRootViewController(animated: true)
}
but now the view didn't change after I clicked the button.
In google login you are presenting the tabbar controller from signinViewcontroller. So just dismiss the tabbar controller when logout button is tapped
#IBAction func didTapSignOut(_ sender: Any) {
//Sign Out
GIDSignIn.sharedInstance().signOut()
//Go to the `SignInViewController`
self.tabBarController?.dismiss(animated: true, completion: nil)
}
change self.navigationController?.pushViewController to self.navigationController?.popToRootViewController (this will have a pop animation)
if you need a push animation, use self.navigationController?.setViewControllers([desVC])
UPDATED 1:
If you don't mind having no push/pop animation, you can directly change the window
let nvc = UINavigationController(rootViewController: desVC)
let window = UIApplication.shared.window
window.rootViewController = nvc
UPDATED 2:
Yea, updating via navigationController would not be proper in your hierarchy. Just change the rootViewController of the window (as stated in Updated 1)

instantiateViewController with the UINavigationController it is embedded in

I'm opening a VC upon a reception of local notification.
func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
application.applicationIconBadgeNumber = 0
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var VC = storyboard.instantiateViewControllerWithIdentifier("PendingRequest") as! PendingRequestVC
let navController = UINavigationController.self(rootViewController: VC)
UIApplication.sharedApplication().keyWindow!.rootViewController = navController
}
The PendingRequestVC that appears has a programmatically Close Tab Item that can't be used with the navController that I created in the code above.
I've tried to insert the Tab Item from the Storyboard and used the Presented Segue instead but I'm still unable to close my PendingRequestVC.
How can I call PendingRequestVC with the NavController it's Embed in instead of creating a new one?
Or how can I close my PendingRequestVC with the created NavController?
Thanks in advance
Why you set the rootViewController of the keyWindow? You may need to presenting a modal view controller:
let rootViewController = UIApplication.sharedApplication().keyWindow!.rootViewController
rootViewController.presentViewController(navController, animated: false, completion: nil)
When you want to close the PendingRequestVC with the created NavController:
// PendingRequestVC
self.dismissViewControllerAnimated(true, completion: {});