Swift 3 and Google Maps with Navigation Drawer - ios

I am creating an application with Swift 3.0 and Xcode 8.2.1. On the main screen you have the Google map in the background and you also have a "NavigationDrawer Acvtiviy". The problem is that when I make a slide to the right or left, the "side" does not appear but the map moves. How can I distinguish between moving the map and showing the right or left side?. My code en UIViewController is:
class MainMapVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let camera = GMSCameraPosition.camera(withLatitude:40.4893538, longitude: -3.6827461, zoom: 5.5)
let mapView = GMSMapView.map(withFrame: .zero, camera: camera)
mapView.isMyLocationEnabled = true
mapView.mapType = .satellite
self.view = mapView
}
#IBAction func leftSideButtonTapped(_ sender: Any) {
let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.centerContainer?.toggle(MMDrawerSide.left,
animated:true, completion:nil)
}
#IBAction func rightSideButtonTapped(_ sender: Any) {
let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.centerContainer?.toggle(MMDrawerSide.right,animated:true, completion:nil)
}
}
And the code in AppDelegate is:
import UIKit
import GoogleMaps
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var centerContainer: MMDrawerController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
GMSServices.provideAPIKey("edcer..erc..er.erc.e.c.")
// Override point for customization after application launch.var rootViewController = self.window!.rootViewControllerlet mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let rootViewController = self.window!.rootViewController!
let mainStoryboard: UIStoryboard = UIStoryboard(name: "MainMap", bundle: nil)
let centerViewController = mainStoryboard.instantiateViewController(withIdentifier: "MainMap") as! MainMapVC
let leftViewController = mainStoryboard.instantiateViewController(withIdentifier: "LeftSideViewController") as! LeftSideViewController
let rightViewController = mainStoryboard.instantiateViewController(withIdentifier: "RightSideViewController") as! RightSideViewController
let leftSideNav = UINavigationController(rootViewController: leftViewController)
let centerNav = UINavigationController(rootViewController: centerViewController)
let rightNav = UINavigationController(rootViewController: rightViewController)
centerContainer = MMDrawerController(center: centerNav, leftDrawerViewController: leftSideNav,rightDrawerViewController:rightNav)
centerContainer!.openDrawerGestureModeMask = MMOpenDrawerGestureMode.panningCenterView;
centerContainer!.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.panningCenterView;
window!.rootViewController = centerContainer
window!.makeKeyAndVisible()
return true
}

Check with following one
mapView.settings.consumesGesturesInView = false

Related

Once i Login why i am not getting HomeViewController as Rootviewcontroller in Swift?

In appdelegate i am getting UserId.. means i am login but when i run second time i am not getting homeviewcontroller as rootviewcontroller why? still it shows phonenumviewcontroller
navigationcontroller -> phonenumviewcontroller -> registrationiewcontroller -> homeviewcontroller
In storyboard navigationcontroller is initialviewcontroller
In registrationviewcontroller i am getting userId which i have saved in keychain.
I dont have signout button so i have written code like below in registrationiewcontroller
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String:AnyObject]
print("terms and condition JSON \(json)")
let jsonObj: String = json["Success"] as? String ?? ""
if jsonObj == "true" {
let userID: String=jsonObj?["userId"] as? String ?? ""
DispatchQueue.main.async {
KeychainWrapper.standard.set(userID, forKey: "USERID")
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController;
UserDefaults.standard.set("NoLogout", forKey:"Signout")
self.navigationController?.pushViewController(viewController, animated: true);
}
}
}
no signout button so added this code in registrationviewcontroller
UserDefaults.standard.set("NoLogout", forKey:"Signout")
this code in appdelegate: getting userId but still homeviewcontroller is not coming as rootviewcontroller, only phonenumviewcontroller is coming why?
var savedUserId: String?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
savedUserId = KeychainWrapper.standard.string(forKey: "USERID")
KeychainWrapper.standard.set(savedUserId ?? "", forKey: "PersonalID")
print("appdelegate userid \(savedUserId)")
logOutString = UserDefaults.standard.string(forKey: "Signout") as NSString? ?? "" as NSString
if logOutString.isEqual(to: "NoLogout") {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
let viewcontroller = storyBoard.instantiateViewController(withIdentifier: "HomeViewController")
let navigationController = UINavigationController(rootViewController: viewcontroller)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
else {
}
return true
}
once registration is completed i need rootviewcontroller as homeviewcontroller... how to get that, please help me with code
From whatever I've gathered, here's what you need to do:
In AppDelegate:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let isUserLoggedIn = UserDefaults.standard.bool(forKey: "isUserLoggedIn") // Give you own check to see if user is logged in
window = UIWindow()
window?.makeKeyAndVisible()
let viewController = isUserLoggedIn ? MainViewController() : LoginViewController()
window?.rootViewController = UINavigationController(rootViewController: viewController)
return true
}
}
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleUserLoggedOut))
}
#objc func handleUserLoggedOut() {
UserDefaults.standard.set(false, forKey: "isUserLoggedIn")
UIApplication.shared.keyWindow?.rootViewController = UINavigationController(rootViewController: LoginViewController())
}
}
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Login", style: .plain, target: self, action: #selector(handleUserLoggedIn))
}
#objc func handleUserLoggedIn() {
UserDefaults.standard.set(true, forKey: "isUserLoggedIn")
UIApplication.shared.keyWindow?.rootViewController = UINavigationController(rootViewController: MainViewController())
}
}
This is only a skeleton. Give both controller different background colours and button action to call handleUserLoginIn and handleUserLoggedOut on respective controllers and see how it works. Play around with it and figure out.
Note: keyWindow is deprecated so you need to use this instead at all places.
let keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
Edit: I've also added the login, logout buttons and set backgroundColors for you to see for yourself the result.

sideMenu not displayed after login

I have included kukushi side menu. I have done things according to the documentation. The screen shot with the codes in app delegate are below:
func setUpHomeVC() {
var window: UIWindow?
let storyBoard = UIStoryboard.init(name: "Dashboard", bundle: Bundle.main)
let contentViewController = storyBoard.instantiateViewController(withIdentifier: "DashboardViewController") as! DashboardViewController
let menuViewController = storyBoard.instantiateViewController(withIdentifier: "MenuViewCOntroller") as! MenuViewCOntroller
SideMenuController.preferences.basic.menuWidth = 240
SideMenuController.preferences.basic.statusBarBehavior = .hideOnMenu
SideMenuController.preferences.basic.position = .sideBySide
SideMenuController.preferences.basic.direction = .left
SideMenuController.preferences.basic.enablePanGesture = true
SideMenuController.preferences.basic.supportedOrientations = .portrait
SideMenuController.preferences.basic.shouldRespectLanguageDirection = true
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = SideMenuController(contentViewController: contentViewController,
menuViewController: menuViewController)
window?.makeKeyAndVisible()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
setUpHomeVC()
return true
}
The identifier, class and module has been added according to the documentation. After login there is dashboard which consist of menu button. On login the code is:
private func goToDashboard() {
let dashboard = UIStoryboard(name: "Dashboard", bundle: nil)
let navView = dashboard.instantiateViewController(identifier: "DashboardViewController") as DashboardViewController
present(navView,animated: false)
}
On dashboard there is a button which have click event:
#IBAction func btnMenuClicked(_ sender: Any) {
print("Menu button has been clicked")
self.sideMenuController?.revealMenu(animated: true)
}
when I click on that button the print function is called but the menu is not revealed.
Can anyone explain it. Thanks in advance.
You can setup your appDelegate like this,
func setUpHomeVC() {
let storyboard = UIStoryboard(name: "Your Login Storyboard", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginVC")
self.window?.rootViewController = initialViewController
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
setUpHomeVC()
return true
}
And in your login event:
private func goToDashboard() {
self.pushVC()
}
private func pushVC() {
let storyBoard = UIStoryboard.init(name: "Dashboard", bundle: Bundle.main)
let contentViewController = storyBoard.instantiateViewController(withIdentifier: "DashboardViewController") as! DashboardViewController
let menuViewController = storyBoard.instantiateViewController(withIdentifier: "MenuViewCOntroller") as! MenuViewCOntroller
SideMenuController.preferences.basic.menuWidth = 240
SideMenuController.preferences.basic.statusBarBehavior = .hideOnMenu
SideMenuController.preferences.basic.position = .sideBySide
SideMenuController.preferences.basic.direction = .left
SideMenuController.preferences.basic.enablePanGesture = true
SideMenuController.preferences.basic.supportedOrientations = .portrait
SideMenuController.preferences.basic.shouldRespectLanguageDirection = true
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = SideMenuController(contentViewController: contentViewController,
menuViewController: menuViewController)
window?.makeKeyAndVisible()
}
Your DashboardVC should be in a navigation controller for sidemenu to present. Try pushing the controller instead of presenting it.If you have the controller in a different storyboard, you can use this function:
func pushVC(storyboardName : String, vcname : String) {
let vc = UIStoryboard.init(name: storyboardName, bundle: Bundle.main).instantiateViewController(withIdentifier: vcname)
self.navigationController?.pushViewController(vc, animated: true)
}
Also, I would suggest you learn about when to push, present, and make root view controllers as all serve different purposes.
I think your current implementation is wrong. The problem is we need to implement and push the view controllers as SideMenuControllers bundle, not separate ViewControlers
If you want to have the side menu after login, then set your login page first in your didFinishLaunchingWithOptions.
Then you can call setUpHomeVC from your loginVC.

After login how to set Sidemenu with MainView controller in swift 4

Please, somebody, advise/guide me. How to achieve this task. I am login from my app and after how to set side menu. i have added the code below.
This is Appdeligate code
fileprivate func createMenuView() {
// create viewController code...
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateViewController(withIdentifier: "GSMngrMainViewController") as! GSMngrMainViewController
let leftViewController = storyboard.instantiateViewController(withIdentifier: "LeftViewController") as! LeftViewController
let nvc: UINavigationController = UINavigationController(rootViewController: mainViewController)
UINavigationBar.appearance().tintColor = UIColor.black
leftViewController.mainViewController = nvc
let slideMenuController = GSExSlideMenuController(mainViewController:nvc, leftMenuViewController: leftViewController)
slideMenuController.automaticallyAdjustsScrollViewInsets = true
slideMenuController.delegate = mainViewController
self.window?.backgroundColor = UIColor.white
self.window?.rootViewController = slideMenuController
//self.window?.rootViewController = loginViewController
self.window?.makeKeyAndVisible()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
DropDown.startListeningToKeyboard()
let userId = UserDefaults.standard.string(forKey: "userId")
if userId == nil{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewController(withIdentifier: "GSLoginViewController")
let navigationCont = UINavigationController.init(rootViewController: loginViewController)
self.window?.rootViewController = navigationCont
}else{
self.createMenuView()
}
GMSServices.provideAPIKey(googleApiKey)
return true
}
Add this code in the ViewController where you want to have a SideMenu
var customView = Side_Menu_ViewController()
func openSideMenu() {
let controller = storyboard!.instantiateViewControllerWithIdentifier("Side_Menu_ViewController") as! Side_Menu_ViewController
addChildViewController(controller)
controller.view.frame = view.frame
controller.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.6)
view.addSubview(controller.view)
controller.didMoveToParentViewController(self)
}
func hideMenu() {
UIView.transitionWithView(self.view, duration: 0.5, options: UIViewAnimationOptions.OverrideInheritedOptions, animations: {
self.customView.view.frame = CGRectMake(self.customView.view.frame.origin.x + 300, 0,self.customView.view.frame.size.width+120,self.view.frame.height);
}, completion: { (finished: Bool) -> () in
})
}
Use two UIViews as shown in the image below - one with black bg and the other with your required things and add the following code in viewDidLoad of SideMenuViewController
SideView.frame = CGRectMake(self.view.frame.width, 0,SideView.frame.size.width,self.view.frame.height)
UIView.transitionWithView(self.view, duration: 0.5, options: UIViewAnimationOptions.OverrideInheritedOptions, animations: {
self.SideView.frame = CGRectMake(self.SideView.frame.origin.x - 210, 0,self.SideView.frame.size.width-130,self.view.frame.size.height);
}, completion: { (finished: Bool) -> () in })

Back button disappears after creating AppDelegate in Swift 3.0

I created the structure as below in xcode 8 swift 3.0.
Before I add AppDelegate code. Back button still appear fine on Apply, Apply Behalf and Profile controller.
I use segue to open page.
But after I add AppDelegate code into Homepage and Login controllers , back button disappears on Apply, Apply behalf and profile controller page.
Can someone help or explain why is this happening ? How to enable back the back button on apply, apply behalf and profile page ?
Thanks.
Home.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet var staffNumberLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
staffNumberLbl.text = UserDefaults.standard.object(forKey: "login") as? String
}
override func viewDidAppear(_ animated: Bool) {
let isUserLoggedIn = UserDefaults.standard.bool(forKey: "loggedIn")
if(!isUserLoggedIn){
self.performSegue(withIdentifier: "loginview", sender: self)
}
}
#IBAction func logoutData(_ sender: Any) {
UserDefaults.standard.set(false, forKey: "loggedIn")
UserDefaults.standard.synchronize();
let loginViewController = self.storyboard!.instantiateViewController(withIdentifier: "loginview") as! LoginViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = loginViewController
appDelegate.window?.makeKeyAndVisible()
}
}
Login.swift
import UIKit
class LoginViewController: UIViewController {
#IBOutlet var loginlbl: UITextField!
#IBOutlet var passlbl: UITextField!
#IBOutlet var login_button: UIButton!
var login: String!
var pw: String!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func loginData(_ sender: Any) {
login = loginLbl.text
pw = passLbl.text
if(login == "" || pw == ""){
return
}
else{
let url = URL(string: "http://localhost/login.php")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
let LoginDataToPost = "login=\(login!)&pw=\(pw!)"
request.httpBody = LoginDataToPost.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
if error != nil {
return
}
else {
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [String: String]
{
DispatchQueue.main.async
{
let message = Int(json["message"]!)
let login = json["login"]
if(message == 1) {
UserDefaults.standard.set(true, forKey: "isUserLoggedIn")
UserDefaults.standard.set(login, forKey: "login")
UserDefaults.standard.synchronize();
self.dismiss(animated: true, completion: nil)
let myViewController:ViewController = self.storyboard!.instantiateViewController(withIdentifier: "ViewController") as! ViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = myViewController
appDelegate.window?.makeKeyAndVisible()
print("Value for login is : \(login!)")
return
}
else {}
}
}
else {}
}
catch let jsonParse {}
}
})
task.resume()
}
}
}
AppDelegate.swift
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let mainStoryBoard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let isUserLoggedIn:Bool = UserDefaults.standard.bool(forKey: "isUserLoggedIn")
if(!isUserLoggedIn) {
let loginViewController = mainStoryBoard.instantiateViewController(withIdentifier: "loginview") as! LoginViewController
window!.rootViewController = loginViewController
window!.makeKeyAndVisible()
}
else {
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
window!.rootViewController = homePage
window!.makeKeyAndVisible()
}
return true
}
}
You are setting rootviewcontroller without embedding navigation controller to it in logoutData & loginData function.
Use this code :
let navigationController = UINavigationController.init(rootViewController: myViewController)
appDelegate.window?.rootViewController = navigationController
Use this code in AppDelegate:
if(!isUserLoggedIn) {
let loginViewController = mainStoryBoard.instantiateViewController(withIdentifier: "loginview") as! LoginViewController
let navigationController = UINavigationController.init(rootViewController: loginViewController)
appDelegate.window?.rootViewController = navigationController
window!.makeKeyAndVisible()
}
else {
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
let navigationController = UINavigationController.init(rootViewController: homePage)
appDelegate.window?.rootViewController = navigationController
window!.makeKeyAndVisible()
}
Remove this from Home.swift,
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = loginViewController
appDelegate.window?.makeKeyAndVisible()
because its not inheriting the properties of Navigation controller
and add it in Appdelegate.swift file
For the other 3 viewcontrollers, you need to add the Navigation controller between eachSegway in order to inherit it or code the button by instantiating the viewcontrollers respectively
After successful login,try to make NavigationController as rootViewController instead of your ViewController
Your back button will start appearing.
In AppDelegate, in else block, instead of this line
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
write this
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "NavigationController") as! UINavigationController
Inside LoginViewController, in the block if(message == 1)
replace
let myViewController:ViewController = self.storyboard!.instantiateViewController(withIdentifier: "ViewController") as! ViewController
with
let navController:UINavigationController = self.storyboard!.instantiateViewController(withIdentifier: "NavigationController") as! UINavigationController
Also set storyboard identifier for UINavigationController in storyboard to NavigationController
Depending on your configuration:
self.navigationItem.hidesBackButton = YES;
OR:
self.navigationController.navigationItem.hidesBackButton = YES;
Or, if you just want to disable the button without hiding it, you can use this.
self.navigationController.navigationItem.backBarButtonItem.enabled = NO;

Best practice for login for Master-Detail App - Swift

I was wondering what is the best practice to implement login screen for Master-Detail application which has SplitView Controller as a root controller. I am using the appDelegate to display the login screen if the user is not logged in. However, when I want to dismiss the loginVC the app goes into blank Detail page instead of the MasterController. Would be a modal login screen better option for Master-Detail app?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as! loginViewController
self.window?.rootViewController = loginVC
return true
let splitViewController = self.window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
splitViewController.delegate = self
return true
And then in my loginVC:
#IBAction func goHome(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = storyboard.instantiateViewControllerWithIdentifier("SplitViewControllerID") as! UISplitViewController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = splitViewController
}
By changing the code of goHome function it works for me. Below is the code:
#IBAction func goHome(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = storyboard.instantiateViewController(withIdentifier: "SplitViewControllerID") as! UISplitViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = splitViewController
splitViewController.preferredDisplayMode = .allVisible
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}

Resources