I'm working on a project, the project doesn't have storyboards, it just have a views as xib files with its own class , the question is : how can I navigate between these xib views ?
or is it possible to embed them in navigation controller ?
I try this code but nothing happened ?
let NC = UINavigationController()
#IBAction func showUserProfile(_ sender: Any) {
print("show Profile")
let vc = UserProfile(
nibName: "UserProfile",
bundle: nil)
NC.pushViewController(vc,
animated: true )
}
this is in app delegate
let mainView = BlockListViewController(nibName: "BlockListViewController", bundle: nil)
window?.addSubview(mainView)
let navigationControll = UINavigationController(rootViewController: mainView)
self.window?.rootViewController = navigationControll
self.window?.makeKeyAndVisible()
and I try to navigate when event occur using this
self.navigationController?.pushViewController(UserProfile(), animated: true)
You can't navigate between instances of UIView
according to apple UINavigationController
A container view controller that defines a stack-based scheme for navigating hierarchical content.
A navigation controller is a container view controller that manages
one or more child view controllers
so basically a stack of UIViewController, defined as [UIViewController]
read more about it in the documentation
What you can do is adding each UIView in a UIViewController and navigate thru that simply.
According to your comment you can predefined them into instance of VC and create a UINavigationController with you'r initial then simply push to the desired UIViewController from the UINavigationController
COMMENT UPDATE
As I got from your comment in the main view you already defining the UINavigationController simply replace NC.pushViewController(vc,animated: true )
with self.navigationController.pushViewController(vc, animated: true )
The problem is you are creating new UINavigationController while you already have the first one embedded
Comment update:
if you're using iOS 13+ with scene delegate use this inside willConnectTo
guard let scene = (scene as? UIWindowScene) else { return }
// Instantiate UIWindow with scene
let window = UIWindow(windowScene: scene)
// Assign window to SceneDelegate window property
self.window = window
// Set initial view controller from Main storyboard as root view controller of UIWindow
let mainView = BlockListViewController(nibName: "BlockListViewController", bundle: nil)
let navigationControll = UINavigationController(rootViewController: mainView)
self.window?.rootViewController = navigationControll
// Present window to screen
self.window?.makeKeyAndVisible()
and call self.navigationController.push
like this
#IBAction func didTap(_ sender: UIButton) {
let secondView = secondVC(nibName: "secondVC", bundle: nil)
self.navigationController?.pushViewController(secondView, animated: true)
}
Related
Let's say I have three view controllers. On the first one, I tap a button and present the second view controller modally. On the second one, I tap a button and store the presenting view controller (first), then set the third view controller as the root view controller. Finally, I have a button on the third view controller that grabs the stored controller and sets that as the root view controller.
When I restore the first view controller, I find that its presentedViewController property is nil. I wonder if I can preserve the navigation stack and have the modal presented when I restore the first view controller?
In this example I'm storing the view controller inside AppDelegate for simplicity.
Code:
FirstViewController.swift
#IBAction func presentViewController(_ sender: Any) {
let storyboard = UIStoryboard(name: "SecondVC", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "Second")
present(controller, animated: true, completion: nil)
}
SecondViewController.swift
#IBAction func secondButtonCLick(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.savedVC = presentingViewController
let storyboard = UIStoryboard(name: "Third", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ThirdVC")
UIApplication.shared.keyWindow?.rootViewController = controller
}
ThirdViewController.swift
#IBAction func thirdBtnTouch(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let rootVC = appDelegate.savedVC
UIApplication.shared.keyWindow?.rootViewController = rootVC
}
I've implemented side bar using SWRevealViewController. But when i do same using Tab bar based view controller, menu icon is invisible only in tab based screens.
Icon is visible in interface builder but invisible in simulator/device.
Functionality is working in every screen, even in tab based view controller.
When i drag from left to right and vice versa, functionality is working fine.
Only the issue is menu icon is invisible in simulator.
Can anyone help me?
Thanks in advance.
below is the swift file for tab
import UIKit
class ItemOneViewController: UIViewController {
#IBOutlet weak var menuBar: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
setMenuBarBtn(menuBar: menuBar)
navigationController!.navigationBar.barTintColor = UIColor.color(.blue)
}
func setMenuBarBtn(menuBar: UIBarButtonItem) {
menuBar.target = revealViewController()
menuBar.action = #selector(SWRevealViewController.revealToggle(_:))
view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.portrait
}
}
Code is similar for three tabs.
I've done below tasks before asking question here
Deleted and recreated screens two times.
Cross checked everything and compared tab bar based scenes source code with other scenes.
googled it.
Below are the images for your reference
Tab based screen with side bar functionality (working good)
Tab based screen without menu icon (Problem persist here , i want menu icon to be displayed)
HomeScreen with menu icon (Working good)
Navigation Controller attribute inspector
my storyboard
Item One View Controller view hierarchy
Item One view Controller related navigation controller scene
You gave to add normal button on HomeViewController
Then directly perform segue through storyboard(from burger menu button).
#IBAction func sideMenuBtnAction(_ sender: UIButton) {
performSegue(withIdentifier: "sideMenu", sender: self)
}
Then on SideMenuController :
import UIKit
import SideMenu
class SideMenuViewController: UIViewController {
#IBOutlet var sideMenuTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
SideMenuManager.default.menuPresentMode = .menuSlideIn
SideMenuManager.default.menuFadeStatusBar = false
SideMenuManager.default.menuWidth = self.view.frame.width / 1.4
SideMenuManager.default.menuShadowOpacity = 0.3
sideMenuTableView.tableFooterView = UIView(frame: .zero)
}
}
You need to create a tabbarController class like below, and assign this ViewController class to tabbar on storyboard ...
I have not tested this code but something like this should work for your case
class ViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let firstSw = setRootViewControllerFor(identifier: "firstViewController") as! SWRevealViewController
let secondsw = setRootViewControllerFor(identifier: "secondViewController") as! SWRevealViewController
let thirdSw = setRootViewControllerFor(identifier: "thirdController") as! SWRevealViewController
self.viewControllers = [firstSw,secondsw, thirdSw]
// Do any additional setup after loading the view.
}
func setRootViewControllerFor(identifier:String)->SWRevealViewController
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sw = storyboard.instantiateViewController(withIdentifier: "sw") as! SWRevealViewController
self.view.window?.rootViewController = sw
let destinationController = self.storyboard?.instantiateViewController(withIdentifier: identifier)
let navigationController = UINavigationController(rootViewController: destinationController!)
navigationController.navigationBar.isHidden=false
navigationController.setNavigationTints() //call your UI method to set
sw.setFront(navigationController, animated: true)
return sw
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
OR Following by doing this there is no need to create a tabbarController
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// create UIWindow with the same size as main screen
window = UIWindow(frame: UIScreen.mainScreen().bounds)
// create story board. Default story board will be named as Main.storyboard in your project.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// create view controllers from storyboard
// Make sure you set Storyboard ID for both the viewcontrollers in
// Interface Builder -> Identitiy Inspector -> Storyboard ID
let firstSw = setRootViewControllerFor(identifier: "firstViewController") as! SWRevealViewController
let secondsw = setRootViewControllerFor(identifier: "secondViewController") as! SWRevealViewController
let thirdSw = setRootViewControllerFor(identifier: "thirdController") as! SWRevealViewController
// Set up the Tab Bar Controller to have two tabs
let tabBarController = UITabBarController()
tabBarController.viewControllers = [firstSw,secondsw, thirdSw]
// Make the Tab Bar Controller the root view controller
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
func setRootViewControllerFor(identifier:String)->SWRevealViewController
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sw = storyboard.instantiateViewController(withIdentifier: "sw") as! SWRevealViewController
self.view.window?.rootViewController = sw
let destinationController = self.storyboard?.instantiateViewController(withIdentifier: identifier)
let navigationController = UINavigationController(rootViewController: destinationController!)
navigationController.navigationBar.isHidden=false
navigationController.setNavigationTints() //call your UI method to set
sw.setFront(navigationController, animated: true)
return sw
}
I have multiple tabs connected via separate navigation controllers. I want to to instantiate same End Pt VC, irrespective of which tab user chooses tabs 1 through 4.
When I select Tab 1 it shows End Pt VC because it is connected via Segue. However when I select other tabs I manually try to push EndPt VC as shown in the tab controller method. But it shows blank screen. How can I present the same End Pt VC irrespective of tab selection?
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "EndPointTVC") as? EndPtListTableViewController{
viewController.selectedTab = self.selectedTab
if let navigator = self.navigationController {
navigator.pushViewController(viewController, animated: true)
}
}
}
You can detect when the UITabBarController changes tab via its delegate UITabBarControllerDelegate. In the following delegate method, you can cast the selected view controller to a UINavigationController (which is what I can make out in the screenshot you attached).
extension MyTabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let myVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MyViewControllerStoryID") as! MyViewController
let navController = viewController as! UINavigationController
navController.viewControllers = [myVC]
print(viewController)
}
}
Now, no matter which tab you choose, a new MyViewController instance is created. Even hitting the same tab multiple times will replace the current instance for a new MyViewController instance.
Try to instantiate the viewcontroller from the storyboard and then present it. Also, make sure that you have given the target viewcontroller the storyboard Id "EndPointTVC" in the Identify section.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier : "EndPointTVC")
viewController.selectedTab = self.selectedTab
self.present(viewController, animated: true)
I have a view controller as my initial view controller.
there's a button in it(GO button) which when the user taps, it should go to another view controller(let's call it Destination view controller with label 'This is where i wanna go'). Meanwhile i want to pass it through a Tabbar controller. The reason is i want to have tabbar in my navigation stack and when users presses back on Destination view controller, it must go to tabbar controller. Picture shows what i want. what can I do to skip tabbar while having it in navigation stack?
You can do that easily inside the IBAction of GO button:
#IBAction func goTapped(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc1 = storyboard.instantiateViewController(withIdentifier: "myTabBarViewController")
let vc2 = storyboard.instantiateViewController(withIdentifier: "myGoalViewController")
let controllers = [vc1, vc2]
self.navigationController!.setViewControllers(self.navigationController!.viewControllers + controllers, animated: true)
}
Good luck!
Going to DestinationViewController could be manually:
if let destinationViewController = self.storyboard?.instantiateViewController(withIdentifier: "Storyboard ID of DestinationViewController") {
self.navigationController?.pushViewController(destinationViewController, animated: true)
}
(Alternatively, you could make a segue from FirstViewController to the DestinationViewController directly in Storyboard)
And in your DestinationViewController, insert the TabbarController to the Navigation sequence manually after view did appear, then you are able to go back to the TabbarController:
class DestinationViewController: UIViewController {
//......
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if self.isBeingPresented || self.isMovingToParentViewController {
var viewControllers = self.navigationController?.viewControllers
if let index = viewControllers?.endIndex.advanced(by: -1),
let tabBarController = self.storyboard?.instantiateViewController(withIdentifier: "Storyboard ID of TabBarController") {
viewControllers?.insert(tabBarController, at: index)
self.navigationController?.viewControllers = viewControllers!
}
}
}
//......
}
I'm currently using a third party called "Form".
In my UIButton, I implement a method which initializes a custom view controller which is a subclass of FormViewController. I initialize FormViewController embedded in navigation controller.
In my FormViewController class, I tried below two methods but none of them did not work.
self.navigationController?.popViewControllerAnimated(true)
self.dismissViewControllerAnimated(true, completion: nil)
Codes for pressing a UIButton:
#IBAction func part1Pressed(sender: AnyObject) {
if let JSON = NSJSONSerialization.JSONObjectWithContentsOfFile("data.JSON") as? [String : AnyObject] {
let initialValues = [
"last_name" : "Nordman"]
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewContainerVC = storyboard.instantiateViewControllerWithIdentifier("viewContainerVC")
let sampleController = Part1_VC(JSON: JSON, initialValues: initialValues)
let rootViewController = UINavigationController(rootViewController: sampleController)
rootViewController.view.tintColor = UIColor(hex: "5182AF")
rootViewController.navigationBarHidden = false
FORMDefaultStyle.applyStyle()
FORMSeparatorView.appearance().setSeparatorColor(UIColor.clearColor())
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
}
}
Thank you!
You are trying to dismiss the view controller when it wasn't presented in the first place.
Instead set the root view controller of the navigation controller to something else (e.g. the screen you want shown after you dismiss the form) and present your form view controller modally:
self.presentViewController(formVc, animated: true, completion: nil)
You can then dismiss the view controller as you intended when you are finished with the form.