I am working on application where after registration process home screen will appear. And the SWRevealViewController has been configure in home screen.
I want to configure SWRevealViewController programmatically.
Below is my code
let storyboard = UIStoryboard(name: "MainSW", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
let rvc:SWRevealViewController = self.revealViewController() as SWRevealViewController
rvc.pushFrontViewController(vc, animated: true)
But it gives me error like below.
Could not cast value of type 'UINavigationController' (0x110d9f860) to
'SWRevealViewController' (0x10dc346b8).
I have tried below link also
SWRevealViewController solution
But it also doesn't help me.
Here is how I have configured it :
I have created 2 UIBarButtonItem as properties of the HomeViewController (I will set them in code)
let leftButton = UIBarButtonItem()
let rightButton = UIBarButtonItem()
In viewDidLoad method:
revealViewController().delegate = self
In viewWillAppear method:
if (revealViewController() != nil) {
revealViewController().rearViewRevealWidth = -50
revealViewController().rightViewRevealWidth = -50
leftButton.image = UIImage(named: "yourImageName")! // check that the image exists, don't use !
leftButton.style = .plain
leftButton.target = revealViewController()
leftButton.action = #selector(SWRevealViewController.revealToggle(_:))
rightButton.image = UIImage(named: "yourImageName")! // check that the image exists, don't use !
rightButton.style = .plain
rightButton.target = revealViewController()
rightButton.action = #selector(SWRevealViewController.rightRevealToggle(_:))
view.addGestureRecognizer(revealViewController().panGestureRecognizer())
view.addGestureRecognizer(revealViewController().tapGestureRecognizer())
}
This is all the code I use to set up SWRevealViewController in my HomeViewController in order to have left and right menu.
You can now use the delegate method to customize the behavior as it pleases you :
extension HomeViewController: SWRevealViewControllerDelegate {
func revealController(_ revealController: SWRevealViewController!, willMoveTo position: FrontViewPosition) {
view.alpha = position == FrontViewPosition.left ? 1.0 : 0.6
}
}
I have set an alpha on the HomeViewController to make it darker when it's not in front.
For the Storyboard part :
Create an UIViewController in the Storyboard.
Change its class to SWRevealViewController
Create 2 more UIViewControllers (1 for the left menu, 1 for the right menu. If you want only 1 menu, apply for either left or right, as you want)
Link the SWRevealViewController to the 2 UIViewControllers with segues (rear and right segues)
Link the SWRevealViewController to your UINavigationController with the front segue.
Link the UINavigationController with your HomeViewController (with root relationship)
Keep in mind that you may also want to create a custom segue for the transition between your RegisterViewController and the HomeViewController.
You can create it programmatically too:
class RegisterToHomeSegue: UIStoryboardSegue {
override func perform() {
let source = self.source as! RegisterViewController
let homeVC = self.destination as! HomeViewController
let window = source.view.window
window?.rootViewController = homeVC
window?.addSubview(source.view)
UIView.transition(from: source.view, to: homeVC.view, duration: 0.50, options: .transitionCrossDissolve, completion: nil)
}
}
And in the Storyboard change the class segue from your RegisterViewController to the SWRevealViewController to this new one RegisterToHomeSegue and give it an identifier. So that in the RegisterViewController you can call :
performSegue(withIdentifier: "yourIdentifier", sender: nil)
And voilĂ , you now have :
Nice transition between your RegisterViewController and your HomeViewController
Your SWRevealController setup properly, with its left and right menu
Left and Right button item with tap gesture to open the corresponding menu
Change alpha on your HomeViewController when it is open
Tell me if it is helping you.
Related
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)
}
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 want to create an app that lets the user click on a button on V1 on the navigation bar. This will segue to V2 where they can press another button on the navigation bar on V2 and it will bring them back to V1 which has the tab bar controller at the bottom. I don't want the tab bar on V2 and I don't want V2 as a tab bar item. When I try this the tab bar disappears on V1 when I segue back to V1 from V2.
TAB BAR CONTROLLER -> TAB BAR ITEM (V1) -> V2(Via navigation bar button item on V1) -> back to V1(Via navigation bar button item on V2)
I have added [self.navigationController, popViewControllerAnimated:YES]; to my button function but it comes up with an error - expected expression in container literal.
Apart from this code I have not got any other code in my app yet.
I am using Xcode 8.0 and Swift 3.0
First create subclass of UITabBarController, Then add properties to AppDelegate
var navController: UINavigationController?
var tabController: MyTabController?
If you want to show tab bar controller on app launch then put these code in AppDelegate in didFinishLaunchingWithOptions
self.window = UIWindow(frame: UIScreen.main.bounds)
let myStoryboard = UIStoryboard(name: "Main", bundle: nil) as UIStoryboard
self.tabController = myStoryboard.instantiateViewController(withIdentifier: "MyTabController") as? MyTabController
//self.navController = UINavigationController(rootViewController: self.tabController!)
//self.window?.rootViewController = self.navController
self.window?.rootViewController = self.tabController
self.window?.makeKeyAndVisible()
return true
If you want to jump on tab bar after login or something else then , add property to that controller
var appDelegate: AppDelegate!
in viewDidLoad
appDelegate = UIApplication.shared.delegate as? AppDelegate
And method should like
func logIntoApp() {
appDelegate.tabController = self.storyboard?.instantiateViewController(withIdentifier: "MyTabController") as? MyTabController
appDelegate.window?.rootViewController = appDelegate.tabController
}
Then in your tab item view controller , create property of AppDelegate and assign delegate as above.
And methods should be like :
#IBAction func showWithTab(_sender: AnyObject) {
let DefaultVC = self.storyboard?.instantiateViewController(withIdentifier: "DefaultViewController") as! DefaultViewController
self.navigationController?.pushViewController(DefaultVC, animated: true)
}
#IBAction func showWithoutTab(_sender: AnyObject) {
let DefaultVC = self.storyboard?.instantiateViewController(withIdentifier: "DefaultViewController") as! DefaultViewController
// You can create your own animation
UIView.transition(from: (appDelegate.tabController?.view)!, to: (appDelegate.navController?.view)!, duration: 0.3, options: UIViewAnimationOptions.curveEaseIn) { (finished) in
self.appDelegate.window?.rootViewController = self.appDelegate.navController
}
// OR you can use like this way
UIView.transition(from: self.view, to: DefaultVC.view, duration: 0.3, options: UIViewAnimationOptions.curveEaseIn) { (finished) in
self.appDelegate.window?.rootViewController = self.appDelegate.navController
}
}
Why not use a simple Tab Bar?
Something like this:
and in VC1 :
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
myTab.removeFromSuperview()
}
I have solved my problem after days of trying to figure out an answer. You need to add this to any view controller.
#IBAction func unwindToViewController (sender: UIStoryboardSegue){
}
Then you can add a segue from bar button item to the exit icon on the view controller.
You can view an image of the VC scene here.
I've asked a question before and it works successfully thanks to the one of the answers How to instantiate a navigation controller from another view controller?, but I have come across a new problem which is , whenever i click a button from a show detail segue, it supposed to navigate to a normal tab with a navigation bar, but it did nothing.
Here's the storyboard
Here's the scenario
1) User click on a button on a firstViewController and it will segue to a thirdViewController which is in show detail
2) User click another button which will then supposed to go to a secondViewController with the codes below
Here's the code
in ThirdViewController
#IBAction func buttonTapped(sender: UIButton) {
guard let tabBarController = tabBarController else { return }
let navController = tabBarController.viewControllers![1] as! UINavigationController
let secondViewController = navController.topViewController as! SecondViewController
secondViewController.name = "My name is TDog"
tabBarController.selectedIndex = 1
}
What did i do wrong? Do i still need to instantiate?
You have to dismiss the actual ThirdViewController but, in this class, you dont know yet UITabViewController so a way to obtain it ( not to re-instantiate but to recall from memory) is to call the rootViewController of your window (it can be done in your project):
#IBAction func buttonTapped(sender: AnyObject) {
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let tabBarController = appDelegate.window!.rootViewController
if tabBarController is UITabBarController {
let tab = tabBarController as! UITabBarController
let navController = tab.viewControllers![1] as! UINavigationController
let secondViewController = navController.topViewController as! SecondViewController
secondViewController.nameString = "My name is TDog"
tab.selectedIndex = 1
}
}
You got to call
self.presentingViewController.dismissViewControllerAnimated(true, completion: nil)
after the following line
tabBarController.selectedIndex = 1
My goal is whenever i click a button on a first view controller, then it will navigate to another controller which is a navigation controller.
firstViewController and secondViewController has no connection or anything.
Picture
I used this code
#IBAction func buttonTapped(sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("secondViewCtrl") as! SecondViewController
self.presentViewController(vc, animated: true, completion: nil)
}
The reason why i instatiate so that I could pass data like
vc.name = "Myname"
The problem with this code is that it doesn't present navigation bar and as well as the tab bar. What should I do to show both?
Updated question
#IBAction func buttonTapped(sender: UIButton) {
guard let tabBarController = tabBarController else { return }
tabBarController.selectedIndex = 1
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("trackYourGenie") as! TrackYourGenieViewController
let navController = tabBarController.viewControllers![1]
let secondViewController = navController.topViewController
vc.name = "Myname"
}
You are instantiating the view controller hence you wouldn't get the navigation bar. To get the navigation bar please instantiate navigation controller and since the second view is only child you would get the second view by default.
#IBAction func buttonTapped(sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("Navigation Controller Id") as! UINavigationController
self.presentViewController(vc, animated: true, completion: nil)
}
The above code should give you the navigation bar.
A safe approach:
guard let tabBarController = tabBarController else { return }
tabBarController.selectedIndex = 1
If you need to access to your tabBarController to pass datas you can do simply:
let navController = tabBarController.viewControllers[1]! as! UINavigationController
let secondViewController = navController.topViewController
Your method could be:
#IBAction func buttonTapped(sender: UIButton) {
guard let tabBarController = tabBarController else { return }
let navController = tabBarController.viewControllers[1]! as! UINavigationController
let secondViewController = navController.topViewController as! SecondViewController
secondViewController.name = "my name"
tabBarController.selectedIndex = 1
}
In your case, the following code should be sufficient :
self.tabBarController.selectedIndex = 1
As UITabBarController is your rootViewController, you can access it with self.tabBarController. You don't have to instantiate UINavigationController as it is in the storyboard.
I can see from your StoryBoard that you have a TabBarController. If your configuration is that and FirstViewController is on first tab and SecondViewController on second tab, you can just change TabBarController selectedIndex property:
#IBAction func buttonTapped(sender: UIButton) {
tabBarController?.selectedIndex = 1
}
If you want to pass data to SecondViewController you can try one of these solutions:
let controller = tabBarController.viewControllers[1] as SecondViewController!
controller.data = "some data"
This soultion could not work since SecondViewController is not ready yet.
Create a singleton class where to save data, then retrieve data in SecondViewController viewDidLoad method
Save data in UserDefaults, then retrieve data in SecondViewController viewDidLoad method (bad solution if information doesn't have to be persistent)
Extend UITabBarController and use it, create a custom var in tabBarController, put data in that variable and then retrieve data in SecondViewController viewDidLoad method
Then clear data if needed.
Navigation will not work from firstViewController as to navigate something we need UINavigationController.
Try Like This