I have a Tabbed App with two tabs... the first tab has the main Action, and the second has Settings that can be updated. I am trying to pass some variables data from Settings to the Action tab. Based on some suggestions, I have used the following code for the Update button:
#IBAction func updateBut(_ sender: Any) {
let myVC = self.storyboard?.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
myVC.totTime = totalTime
myVC.timeInt = intTime
self.present(myVC, animated: true, completion: nil)
}
The data does pass to the first view controller, however, the tabs have disappeared on this view now. So, how can I get the tabs back on the screen? I am quite the beginner to any form of app development, and am just trying to learn by doing... the Tabbed App has been created using one of the Xcode New Project templates. Thanks.
try this way
(self.tabBarController?.viewControllers?[0] as! FirstViewController).totTime = totalTime
(self.tabBarController?.viewControllers?[0] as! FirstViewController).timeInt = intTime
self.tabBarController?.selectedIndex = 0
self.tabBarController?.tabBar.isHidden = false try this
A much better way to pass data by using protocols, you can define a protocol like below
protocol PassDataDelegate{
func updateFirstVc(totalTime:String)
}
and in your SecondViewController class have a delegate property like below
class SecondViewController:UIViewController{
myDelegate:PassDataDelegate?//declaration part
#IBAction func updateBut(_ sender: Any) {
myDelegate.updateFirstVc(totalTime:totalTime)
}
}
And finally in your UITabController class implement the protocol
class myTabController:UITabController,PassDataDelegate{
var firstController:FirstViewController? //declaration part
var secondController:SecondViewController?
override func viewDidLoad(){
super.viewDidLoad()
//initialize your view controller here
self.firstViewController = FirstViewController()
self.secondViewController = SecondViewController()
self.secondViewController.myDelegate = self //assign delegate to second vc
self.viewcontrollers = [firstController, secondController]
}
updateFirstVc(totalTime:totalTime){
self.firstViewController?.totTime = totalTime
self.selectedIndex = 0// here change the tab to first vc if you want to switch the tab after passing data
}
}
I am new to iOS correct me If I am wrong,
The reason why the TabBar is not visible since you are instantiating new FirstViewController which is present on top of your TabBar.
TabBar by default does this Job or Add the new viewController to the TabBar Stack.
tabBarController.viewControllers.append(myVC)
For passing the data TabBar holds the reference of all its ViewControllers. So you can set or get in each other ViewControllers like this
var yourData{
set{
let yourVC = self.tabBarController?.viewController[0] as? FirstViewController ?? ErrorClass
yourVC.dataObj = newValue
}
get{
let yourVC = self.tabBarController?.viewController[0] as? FirstViewController ?? ErrorClass
return yourVC.dataObj
}
Related
I have a view controller like below.
This view is attached with a tabBarController. The tabBarController has 5 viewControllers and I have to present the 5th viewController of tabBar from another page. So I used the below codes for present that viewController
#IBAction func onClickUserProfile(_ sender: Any) {
let navVc = self.storyboard?.instantiateViewController(withIdentifier: "ProfileVC")as! ProfileVC
navVc.userId = Int(self.userId)
navVc.navigationItem.hidesBackButton = true
navVc.tabBarController?.tabBar.isHidden = false
self.navigationController?.pushViewController(nxtVc, animated: true)
}
But after execute the code it resulting the view controller as the below image.
The view undergoes the tabBar. Anyone help me to push to a tabBar view.
You need to set the selected UIViewController from UITabBarController something like this should work .
self.tabBarController?.selectedViewController = self.tabBarController?.viewControllers![1]
where tabBarController?.viewControllers returns the array of current ViewControllers embedded in the UITabBarController .
Your code should be something like this.
#IBAction func onClickUserProfile(_ sender: Any) {
let vc = self.tabBarController?.viewControllers![1] as! ProfileVC // use your index
vc.userId = Int(self.userId)
self.tabBarController?.selectedViewController = vc
}
Note: Don't create an instance of the UIViewController as .instantiateViewController(withIdentifier:) use the already existed
ones in the array tabBarController?.viewControllers, creating new
instance will be treated as new one and gives the problem you have up
there .
I have an mainViewcontroller in that one button called get value.Then i am calling dataviewcontroller to select any item in collection view cell.Once user select any cell.That particular dataviewcontroller will dismiss and while dismiss it will have the user selected item name and it will display in mainViewcontroller .Now the view controller is not dismissing.
Here the code :
In my mainViewcontroller:
var SelectedName: String? = ""
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
currentTF.text = SelectedName
}
Now dataviewcontroller :
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView.cellForItem(at: indexPath) != nil {
selectedNamesss = allitems[indexPath.row] as String
}
calldismiss()
print(selectedNamesss)
}
func calldismiss() {
if let presenter = presentingViewController as? mainViewcontroller {
presenter.SelectedName = selectedNamesss
}
dismiss(animated: true, completion: nil)
}
Now how can i solve this.My viewcontroller is not dismising and values also not showing.
Thanks in advance ~
My Suggestion is to use "UnwindSegue" technique, which is simply works like "PerformSegue", So you can send back values very easily using prepare for segue and will be back to main controller. Here is tutorial for unwind segue. Or you can find more from google.
For The problem where data is not showing, problem is with this condition:
if let presenter = presentingViewController as? mainViewcontroller {
presenter.SelectedName = selectedNamesss
}
this condition will never be true as the presentingViewController would always be a UINavigationController. so you need to change that may be something like follows:
if let presenter = (presentingViewController as! UINavigationController).viewControllers.first! as? mainViewcontroller {
presenter.SelectedName = name
}
Here i am using viewControllers.first! in condition as mainViewcontroller was at first index of the viewControllers array. Check the viewControllers array and find the index of mainViewcontroller and make changes accordingly.
I made this changes and the code is working for me. I am getting the selected name on the mainViewcontroller.
Also i would like to mention that this is not the right way to transfer data backwards. You can use delegates, blocks or unwind segue to achieve this.
Though this is working i am attaching a gif to show this working.
Regarding the issue where your controller is not being dismissed, i am presenting the controller in following way:
let dataVC = self.storyboard?.instantiateViewController(withIdentifier: "dataviewcontroller") as! dataviewcontroller
self.present(vc, animated: true, completion: nil)
Try this and see if this helps you :)
I'm working on an IOS app that uses tabs for navigation. The app gives access to users to a video library. However there are two types of users, those who purchase individual episodes and those who are subscribed. The former only have access to the videos they purchased while the latter have access to every single video in the library.
In my tab bar (in storyboard) I have a Purchases button, but if the user is a subscriber I don't want this tab to appear.
The app checks if a user is logged in upon launching and checks to see what the user status is (buyer or subscriber). I would like to know if there is a way to load different sets of tabs depending on the user type.
If any one could steer me in the right direction I'd really appreciate it. Thanks!
From the top of my head I can think of several ways but this could do it. I am assuming that you somehow know which kind of user is logged in based on the server's response or something similar.
Create your own class that mutates depending on the user eg:
MyTabBarController: UITabBarController {
override func viewDidLoad() {
if (currentUser == admin) {
setupAdminTabBar()
} else {
setupRegularTabBar()
}
}
}
then on each function do something like
func setupRegularTabBar() {
//do this many as many times as root view controllers you want
let searchNavController = createMyNavController(unselectedImage: UIImage(named: "yourimage"), selectedImage: UIImage(named: "yourimage"), rootViewController: UserSearchController(collectionViewLayout: UICollectionViewFlowLayout()))
//add the other controllers that you create like the one above...
viewControllers = [searchNavController]
}
fileprivate func createMyNavController (unselectedImage: UIImage, selectedImage: UIImage, rootViewController : UIViewController = UIViewController()) -> UINavigationController {
let viewController = rootViewController
let navController = UINavigationController(rootViewController: viewController)
navController.tabBarItem.image = unselectedImage
navController.tabBarItem.selectedImage = selectedImage
return navController
}
Subclass UITabBarController and use setViewControllers(_:animated:):
class MyTabBarController: UITabBarController
{
override func viewDidLoad()
{
super.viewDidLoad()
switch user
{
case .buyer:
guard let vc1 = storyboard?.instantiateViewController(withIdentifier: "first"),
let vc2 = storyboard?.instantiateViewController(withIdentifier: "second") else
{
return
}
setViewControllers([vc1, vc2], animated: true)
case .subscriber:
guard let vc3 = storyboard?.instantiateViewController(withIdentifier: "third"),
let vc4 = storyboard?.instantiateViewController(withIdentifier: "fourth") else
{
return
}
setViewControllers([vc3, vc4], animated: true)
}
}
}
You can use the setViewControllers function of UITabBarController:
func setViewControllers(_ viewControllers: [UIViewController]?, animated: Bool)
Set up all the possible controllers in the storyboard with a separate outlet for each one. Then pass an array of the outlets you wish to appear to setViewControllers
I have 2 controllers: ViewController and GalleryViewController(with the collection view on it). From the storyboard I set for the collectionView in GalleryViewController Scrolling Enabled to false. Now, how can I change it to true from the ViewController?
I've tried this:
var vc: GalleryViewController?
vc.collectionView.scrollEnabled = true
but it does not work. Is there another solution with which I can change scrolling from another controller(ViewController)?
your code will create a new instance of GalleryViewController and you need to use the existing one.
You have a number of options, partly depending on how you navigate from ViewController to GalleryViewController.
If you are creating the Gallery View from your initial controller, then you should use prepareForSegue, something like this
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
if segue!.identifier == "GallerySegueOrWhateverYouHaveCalledIt" {
let viewGalleryController:ViewGalleryController = segue!.destinationViewController as ViewGalleryController
let collectionViewLink = viewGalleryController.collectionView
}
}
If you're using a Tab Controller, and assuming you know the index of your GalleryView, let's call it indexGalleryView, then it's even easier
var vc = tabBarController!.viewControllers![indexGalleryView] as! GalleryViewController
vc.collectionView.scrollEnabled = true
And if you have a ViewController -> Container -> Embed GalleryViewController -> CollectionView, you can get a handle to the embedded ViewController in the viewDidLoad of the top level controller like this
for vc in self.childViewControllers
{
if vc.isKindOfClass(GalleryViewController)
{
myGalleryViewController = vc as! GalleryViewController
}
}
once you have myGalleryViewController you should be able to access everything on the child view
I'm a beginner. I am doing a popover when a button is pressed which then instantiates another view controller where the user can select from 5 choices. I want to be able to save the sender.tag of the button from the first view controller (where code snippet below came from) and pass it to the second where I can save them together to Parse. I'm not using a segue so I can't pass it that way. Thanks in advance!
func showPopover(sender: UIButton) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("SelectionViewController")
vc!.modalPresentationStyle = .Popover
vc!.preferredContentSize = CGSizeMake(150, 30)
if let presentationController = vc!.popoverPresentationController {
presentationController.delegate = self
presentationController.permittedArrowDirections = .Up
presentationController.sourceView = self.view
presentationController.sourceRect = sender.frame
self.presentViewController(vc!, animated: true, completion: nil)
}
}
The easiest way would be to declare a variable var myVariable = Int() outside of either view controller class. Then, inside of your main VC and before you instantiate the popover, save the tag to the variable. You'll be able to use it inside the popover.
You could just use a segue (why aren't you?)
You put a property for the tag in the popover and set it in the first view controller, inside
func prepareForSegue(_ segue: NSStoryboardSegue, sender sender: AnyObject?).
To perform the segue, you just use
func performSegueWithIdentifier(_ identifier: String, sender sender: AnyObject?)
, inside your function
func showPopover(sender: UIButton)
If you don't want to use a segue you can simply cast the controller you get from instantiateViewControllerWithIdentifier() to your subclass.
Swift 2.0
func showPopover(sender: UIButton) {
guard let vc = self.storyboard?.instantiateViewControllerWithIdentifier("SelectionViewController") as? MYViewController
} else {
print("This is not the view controller you were looking for..."
return
}
vc.myVariableName = sender.tag
...
}