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
}
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)
}
When I launch a build for the application the login and signup work just fine but when it transfers to the HomeVC storyboard it appears empty. To make sure that it is referenced correctly I put labels on it and those were appearing during builds what just really remains invisible is the navigation bar. Pls help :)
How the HomeVC storyboard is referenced in Login and Signup
Login:
else {
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as? HomeViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
SignUp:
func transitionToHome(){
let homeViewController = storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as? HomeViewController
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
Here is the login storyboard
The navigation bar is clearly apparent in the storyboards
You could try to use a segue
// This is used to perform the segue with the approporiate identifier
self.performSegue(withIdentifier: "Your unique identifer of the seugue", sender: self)
// Prepare for segue is used if you want to modify some properities in the desintation viewcontroller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Your identifier of the segue" {
// This is used to fetch the destination and cast it to pass over the values
if let dc = segue.destination as? YourClassOfTheDestination {
// Here can you type into dc and pass over the values
//Example
dc.curentFruit = "Pear"
}
}
}
Here is an image on how to specify the custom identifier of the segue in the storyboard. Here is the image
If you don't want the navigation bar to be visible in certain screens you can simply use:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.isHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.isHidden = false
}
Remember to make it visible again when the view disappears.
Great question, hope the answer helps!
I believe the issue is you are making the view controller the key window and you are not adding the navigation controller. Try making the home view controller's navigation controller the key window.
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 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 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.