Navigation Between UIViewControllers Swift 2.2 - ios

I have 3 ViewControllers and want to navigate between then without appearing the second one.
what actually i want to do something like this:
FirstController
override func viewDidLoad() {
super.viewDidLoad()
let secondController = SecondController();
secondController.showThird();
}
SecondController
override func viewDidLoad() {
super.viewDidLoad()
super.didReceiveMemoryWarning()
}
func showThird() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("thirdId")
self.navigationController?.pushViewController(controller, animated: true)
}
ThirdController
override func viewDidLoad() {
super.viewDidLoad()
}

appdelegate.swift
You can push the second Viewcontroller without animation and next line you need to push Third Viewcontroller
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let controllerOne = storyboard.instantiateViewControllerWithIdentifier("oneId")
self.navigationController?.pushViewController(controllerOne, animated: false)
let controllerTwo = storyboard.instantiateViewControllerWithIdentifier("secondId")
self.navigationController?.pushViewController(controllerTwo, animated: false)
let controllerThree = storyboard.instantiateViewControllerWithIdentifier("thirdId")
self.navigationController?.pushViewController(controllerThree, animated: true)
}
Hopefully It works for you.

Related

Tabbar controller unexpected dismiss behavior

I have a UITabBarController with two childs (A and B) and I present a third controller C from UITabBarController but if I call dismiss on controller A, controller C gets dismissed.
How can this happen even if controller C is not part of controller A's hierarchy? If this is the default behavior can I change it?
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let tab = UITabBarController()
let a = A()
let b = B()
tab.viewControllers = [a, b]
window?.rootViewController = tab
window?.makeKeyAndVisible()
DispatchQueue.main.asyncAfter(deadline: .now()+5) {
tab.present(C(), animated: true, completion: nil)
}
return true
}
}
class A: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.asyncAfter(deadline: .now()+10) {
self.dismiss(animated: true, completion: nil)
}
}
}

Framework ViewController View Not showing

I am trying to create a framework (Login VC) which contains a view controller. I have successfully imported the framework and presented the VC, but the view is not showing. I have a print function in the imported viewDidLoad and it is printing. What am I missing?
Framework VC:
public class LoginVC: UIViewController {
#IBOutlet weak var button: UIButton! {
didSet {
button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
}
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func viewDidLoad() {
super.viewDidLoad()
print("View Loaded") // Firing
}
#objc func buttonPressed() {
print("hello")
}
}
Framework VC Xib:
This is view debugger when I present the framework VC
-- Update: This is how I am showing the VC ---
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let homeViewController = LoginVC()
homeViewController.view.backgroundColor = UIColor.white
window!.rootViewController = homeViewController
window!.makeKeyAndVisible()
return true
}
-- Update --
Since many comments relate to the app delegate, I first present a general ViewController which then will present my login framework VC.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let homeViewController = ViewController()
homeViewController.view.backgroundColor = UIColor.white
window!.rootViewController = homeViewController
window!.makeKeyAndVisible()
return true
}
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton! {
didSet {
button.addTarget(self, action: #selector(presentNext), for: .touchUpInside)
}
}
#objc func presentNext() {
let loginVC = LoginVC()
present(loginVC, animated: true, completion: nil)
}
}
Now, when I present the login framework, all I get is a black screen.
-- Update --
I can change the background color of the view in viewdidLoad, but the xib views are not shown. Why is this?..
Frameworks with xibs connected to viewController require explicit loading from the bundle.
Usually when we create a cocoaTouch UIViewController with xib, this is handled for us. However, when using frameworks, it is not handled.
To solve this, I add load the xib in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// Frameworks require loading of the xib to connect xib to view controller
let bundle = Bundle(for: type(of: self))
bundle.loadNibNamed("viewControllerName", owner: self, options: nil)
}
You need to call your presentNext() after the ViewController has actually appeared -- not in viewDidLoad, and not even in viewWillAppear.
Like this:
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
presentNext()
}
#objc func presentNext() {
let loginVC = LoginVC()
present(loginVC, animated: true, completion: nil)
}
}
Here's the working test project:
https://github.com/drewster99/SO_LoginVC
Also, maybe double-check that your ViewController.xib has the IBOutlet actually attached for the button. It's actually got to be that. Everything else looks good.
Here's what I've got:
AppDelegate:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let homeViewController = ViewController()
homeViewController.view.backgroundColor = UIColor.white
window!.rootViewController = homeViewController
window!.makeKeyAndVisible()
return true
}
}
ViewController.swift:
import UIKit
import LoginFrameworkThing
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton! {
didSet {
button.addTarget(self, action: #selector(presentNext), for: .touchUpInside)
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
#objc func presentNext() {
print("Presenting next...")
let loginVC = LoginVC()
present(loginVC, animated: true, completion: nil)
}
}
The button is connected in ViewController, and LoginVC (both .xib and .swift) exist in the framework.
I updated the sample project. Check the link.

Calling delegate function from AppDelegate not working

I am trying to call delegate function in AppDelegate, but seems like it never get invoked.
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,appdelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let navigationController = window?.rootViewController, let
viewController = navigationController.childViewControllers.first as? ViewController {
viewController.delegate = self
}
// Override point for customization after application launch.
return true
}
func callfromDelegte(indicator: UIActivityIndicatorView) {
indicator.stopAnimating()
}
ViewController-:
import UIKit
protocol appdelegate:class {
func callfromDelegte(indicator:UIActivityIndicatorView)
}
class ViewController: UIViewController {
#IBOutlet weak var indicator: UIActivityIndicatorView!
weak var delegate:appdelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
indicator.startAnimating()
indicator.hidesWhenStopped = true
}
#IBAction func rotateAction(_ sender: UIButton) {
if delegate != nil{
delegate?.callfromDelegte(indicator: indicator)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Delegate is always nil, it never goes inside function. What is that i don't
now about delegates yet? How does Google GIDSignInDelegate and its delegate functions get called inside AppDelegate from controller class? I know it might be very stupid question but I would still like to know.Thanks
Ok it worked as i have not embeded my controller with navigationController. So it was not going inside if let. It worked simply like this-:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// if let navigationController = window?.rootViewController, let
// viewController = navigationController.childViewControllers.first as? ViewController {
// viewController.delegate = self
// }
// Override point for customization after application launch.
let controller = window?.rootViewController as! ViewController
controller.delegate = self
return true
}
You cannot create the Viewcontroller object directly and set the delegate inside your app delegate. You need to access the Viewcontroller object first because it is the inside the rootViewController so you need to implement like this
if let navigationController = window?.rootViewController, let
viewController = navigationController.childViewControllers.first as? ViewController {
viewController.delegate = self
}
You can try to get AppDelegate instance from shared application. Hope it will help
This is Swift 3
#IBAction func rotateAction(_ sender: UIButton) {
let delegate = UIApplication.shared.delegate as? AppDelegate
delegate?.callfromDelegte(indicator: indicator)
}

can't change title navigation Controller

I can't change the title of my navigationBar in the options view. I am not using Storyboards. I can't add button too.
This is my App Delegate code :
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let viewController = MenuTableViewController(nibName: nil, bundle: nil) //ViewController = Name of your controller
let navigationController = UINavigationController(rootViewController: viewController)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
This is my MenuTabeViewController file
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Options", style: .plain, target: self, action: #selector(handleOptions))
}
func handleOptions() {
let optionViewController = optionsViewController()
present(optionViewController, animated: true, completion: nil)
}
this is my options file
class optionsViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
view?.backgroundColor = UIColor.white
//I've tried 3 solutions
self.navigationItem.title = "Options"
self.title = "Options"
self.navigationBar.topItem?.title = "Options"
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
dismiss(animated: true, completion: nil)
}
}
I believe the issue is due to the fact that you're not setting up the new navigation / view controller properly when presenting it.
When presenting your new UINavigationController, as you did previously in the AppDelegate, you'll want to create a UIViewController and set it as the rootViewController. So you'll want something like OptionsNavController and OptionsViewController instead of a single nav controller.
Then in your OptionsViewController simple call self.title = #"Options".
EDIT
I'm including an example below.
func handleOptions() {
let optionsViewController = OptionsViewController()
let optionsNavController = UINavigationController(rootViewController: optionsViewController)
present(optionsNavController, animated: true, completion: nil)
}
so then as stated above, call self.title = #"Options" in OptionsViewController.

Swift View Layout below tabbar

class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.backgroundColor = UIColor.whiteColor()
self.window?.makeKeyAndVisible()
let vc = ViewController()
vc.tabBarItem = UITabBarItem(...)
...
let tabbar = UITabBarController()
tabbar.setViewControllers([...,vc,...], animated: false)
self.window?.rootViewController = tabbar
tabbar.selectedIndex = 2
return true
}
}
class ViewController: UIViewController {
override func loadView() {
super.loadView()
self.view.backgroundColor = UIColor.yellowColor()
//self.automaticallyAdjustsScrollViewInsets = false;
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
}
I am not using a story board.
The above causes the ViewControllers view to extend below the tab bar. How can i stop this?
I've tried setting the views frame to
CGRectMake(0, 0, self.view.frame.width, self.view.frame.height - tabBarController.view.frame.height))
but that did not work.
You can use the edgesForExtendedLayout property of UIViewController to set which edges to extend under navigation bars. If you don't want any, you can simply say:
self.edgesForExtendedLayout = .None
For Swift 5 or above
self.edgesForExtendedLayout = []

Resources