I have a ViewController with 2 sub containers. The first sub container points to a ViewController with a TabBar inside it. The second sub container is a ViewController that contains a collection view. Now my issue is trying to access the first sub containers TabBar so that when an Item is clicked, I can know which item is clicked and process my data.
The main ViewController has a class. All the other sub containers for that ViewController also have a class. Here is the .h for my sub container with the Tab Bar:
#import <UIKit/UIKit.h>
#interface home_tab : UIViewController <UITabBarControllerDelegate>{
}
#end
.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"working");
}
Now when clicking on the Tab Bar that is populated, didSelectViewController is never called.
I am using storyboard.
Suggestions and thoughts?
Try this on your viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
[[self tabBarController]setDelegate:self];
// Do any additional setup after loading the view, typically from a nib.
}
It's just an suggestion :)
[[self tabBarController]selectedIndex] This will return the index of the selected tab.
I think you have a couple problems atleast from what I can see here,
You are using a TabBar inside of a ViewController, not a UITabBarController, thus you need to use UITabBarDelegate not UITabBarControllerDelegate. You will have to manage the view controllers or whatever view you will want to be loaded on your own most likely with the delegate callback:
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
Also you dont have a UITabBar defined in your controller, therefore your ViewController has no idea you have a UITabBar in your Storyboard. You need something like this:
#interface ViewController : UIViewController <UITabBarDelegate>
#property (weak, nonatomic) IBOutlet UITabBar *tabBar;
#end
Then you will need to Control drag from the ViewController to your UITabBar and back to connect the Delegate in your Storyboard.
Id recommend using a UITabBarController so you dont have to manage the views yourself depending on what you are trying to accomplish.
Hope this helps!
the didSelectViewController method is part of the UITabBarControllerDelegate Protocol and is called on the UITabBarController's delegate. Did you set the delegate of the tab bar controller to the current instance of your subcontainer? Inside ViewDidLoad: do something like this:
[self.tabBarController setDelegate:self];
You can also set a delegate on the UITabBar rather than the controller, and the UITabBarDelegate Protocol contains a method tabBar:didSelectItem: that would be called.
Related
I want to segue back from ViewControllerTwo to ViewControllerOne. I created a button that is responsible for doing that, but my problem is that the button is part of custom UIView class that is added to ViewControllerTwo, the button is not a part of the main view of ViewControllerTwo.
So in the custom UIView class I have the method that reacts if the button is clicked...
-(void)buttonClicked{
[SecondViewController performSegueWithIdentifier: "ShowFirstViewController" sender:nil];
}
When I do this I get an error: "performSegueWithIdentifier not a method of class" which makes sense.
So how can I segue between two viewcontrollers where the button responsible for the segue is not actually part of either view controller and is in a different class.
I think you can have a delegate call back to your SecondViewController and implement the performSegueWithIdentifier in the delegate callback method in SecondViewController.
It goes like this:
Above your custom UIView class interface create a protocol like this
#protocol CustomViewDelegate <NSObject>
- (void)buttonDidTap;
#end
Then create a property in your interface
#property (nonatomic, weak) id <CustomViewDelegate> delegate;
In your custom UIView *.m add this
-(void)buttonClicked{
[self.delegate buttonDidTap];
}
Conform the protocol to your SecondViewController like this
#interface SecondViewController: UIViewController <CustomViewDelegate>
set the delegate in your viewDidLoadMethod like this
-(void)viewDidLoad{
[super viewDidLoad];
self.yourCustomView.delegate = self;
}
implement this method inside the view controller .m file
- (void)buttonDidTap{
[self.performSegueWithIdentifier: "ShowFirstViewController" sender:self];
}
I'm more of a swift guy i think this should work fine.
iOS 9.3, Xcode 7.3, ARC enabled
This is what I'd do to troubleshoot:
Step 1: Make sure that you have a proper storyboard identifier for the view controllers you wish to segue between. The views simply attach to the view controllers, custom or not.
To do this, go to "*.storyboard" show the Utilities (right pane) and navigate to the Identity Inspector. Make sure you have "ShowFirstViewController" entered in the Storyboard ID field.
I have a button on UIViewController on click of that button an UIview gets poped up like alertview which has tableview in it.Now on selection of table cell i would like to segue to the detail viewcontroller
Here's the link to which i refered but none of them worked for me
For alertview i have used (https://github.com/kwent/ios-custom-alertview)
Thanks.
#yar1vn's answer is right, however, I'll describe more precisely what you need to do.
Custom alert view from your link has a delegate property, which should conform to protocol
#protocol CustomIOS7AlertViewDelegate
- (void)customIOS7dialogButtonTouchUpInside:(id)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
#end
that means you should implement this method in your UIViewController.
in .h file:
#interface YourViewController : UIViewController <YourViewController>
...
#end
in .m file:
#implementation YourViewController
...
- (void)customIOS7dialogButtonTouchUpInside:(id)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self performSegueWithIdentifier:#"YourSegue" sender:nil];
}
and set the delegate when creating alertView:
[alertView setDelegate:self];
#"YourSegue" is the segue from the controller which shows alertView to the detail view controller.
I disagree that you should use UIAlertController, since if your deployment target is iOS 7 (which is reasonable) you should not use new features of iOS 8
EDIT:
if you want to launch segue from tap on table view cell, you should call [self performSegueWithIdentifier:#"YourSegue" sender:nil] from tableView's delegate method -tableView:didSelectRowAtIndexPath:
I assume you have set current view controller as tableView's dataSource and delegate, so add to your view controller
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"YourSegue" sender:nil];
}
EDIT 2:
though setting the UIView as delegate is not the best approach, we can handle it :)
I see two solutions:
the first is to add the controller as the property to your view like this:
#interface YourView : UIView <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) YourViewController *parentController;
...
somewhere (probably, in -viewDidLoad) you set this property as
youViewInstance.parentController = self;
and the in view's delegate method call
[self.parentController performSegueWithIdentifier:#"YouSegue" sender:nil]
the second one is to simply set the controller as tableView's delegate and call performSegue: from its method. And you should describe all details more completely :)
You shouldn't use 3rd party AlertViews anymore. You can use the AlertController provided with iOS 8 SDK.
I don't know how this AlertView works but the readme mentions a delegate. Did you try calling the segue from the delegate method?
I am relatively new to Xcode and have tried to find the answer by searching, without luck.
My app has 5 View Controllers, V1 through V5, which are embedded in one Tab Bar Controller. Each View Controller has a segue to one and the same Setup Menu View Controller. The Menu changes some labels on the View Controllers. I use a delegate to make sure that the View Controller that calls the Menu gets updated with the new settings when you leave the Menu. However, this allows me to modify only the labels on the View Controller that called the Menu Controller, not on the 4 other ones.
I work form a Story Board. Is there a simple way to set the UILabels on V2, V3, V4 and V5 from V1 (and vice versa), or even better, set the labels on V1 through V5 from the Menu View Controller (which is not embedded in the Tab Bar Controller)?
I have seen something that could help here, but this seems rather complicated for what I want. The label changes I need are quite simple and are all predefined. Is there a method that is called every time you switch tabs in a tabbed application? Similar to ViewDidLoad?
This sounds like a good time for NSNotificationCenter. You are going to have your MenuViewController generate a notification with the new data that should be updated in your other view controllers:
// User has updated Menu values
[[NSNotificationCenter defaultCenter] postNotificationName:#"MenuDataDidChangeStuffForLabels" object:self userInfo:#{#"newLabelValue" : labelText}];
In your V1, V2, etc. you can add subscribe to these notifications using this code in your viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
// Subscribe to NSNotifications named "MenuDataDidChangeStuffForLabels"
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateLabelText) name:#"MenuDataDidChangeStuffForLabels" object:nil];
}
Any object that subscribes using that code will call the updateLabelText method anytime a notification with that name is posted by the MenuViewController. From that method you can get the new label value and assign it to your label.
- (void)updateLabelText:(NSNotification *)notification {
NSString *newText = notification.userInfo[#"newLabelValue"];
myLabel.text = newText;
}
What I would do is subclass the tab bar controller and set that as the delegate for the menu view controller. From there, you can get updated when the labels are supposed to change and then communicate with the 5 tabs and update the labels.
Alternatively, you could use NSNotifications to let all the 5 view controllers know when settings change.
Lastly, you could add the menu settings to a singleton and have all of the view controllers observe the various properties that can change.
The label changes I need are quite simple and are all predefined. Is there a method that is called every time you switch tabs in a tabbed application? Similar to ViewDidLoad?
Regarding this question, the methods you're looking for are viewWillAppear: and viewDidAppear.
Here is a very simple solution if your workflow is also simple. This method changes all the labels from the different ViewControllers directly from what you call the Menu ViewController.
Let's say you have the following situation :
The blue ViewController is of the FirstViewController class. The green ViewController is of the SecondViewController class. The labels on each of those are referenced by the properties firstVCLabel and secondVCLabel (on the appropriate class' header file). Both these ViewControllers have a "Modal" button which simply segues modally on touch up inside.
So when you clic on any of these two buttons, the orange ViewController (of ModalViewController class) is presented. This ViewController has two buttons, "Change Label" and "Back", which are linked to touch up inside IBActions called changeLabel: and back:.
Here is the code for the ModalViewController :
#import "ModalViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface ModalViewController ()
#end
#implementation ModalViewController
// Action linked to the "Change Label" button
- (IBAction)changeLabel:(id)sender {
// Access the presenting ViewController, which is directly the TabBarController in this particular case
// The cast is simply to get rid of the warning
UITabBarController *tabBarController = (UITabBarController*)self.presentingViewController;
// Go through all the ViewControllers presented by the TabBarController
for (UIViewController *viewController in tabBarController.viewControllers) {
// You can handle each ViewController separately by looking at its class
if ([viewController isKindOfClass:[FirstViewController class]]) {
// Cast the ViewController to access its properties
FirstViewController *firstVC = (FirstViewController*)viewController;
// Update the label
firstVC.firstVCLabel.text = #"Updated first VC label from Modal";
} else if ([viewController isKindOfClass:[SecondViewController class]]) {
SecondViewController *secondVC = (SecondViewController*)viewController;
secondVC.secondVCLabel.text = #"Updated second VC label from Modal";
}
}
}
// Action linked to the "Back" button
- (IBAction)back:(id)sender {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
For the sake of completeness, here are FirstViewController.h :
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *firstVCLabel;
#end
And SecondViewController.h :
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *secondVCLabel;
#end
There is no relevant code in the implementation of these classes.
Thanks a lot guys, I am impressed by your quick responses. In this particular case, viewWillAppear does the trick:
- (void)viewWillAppear:(BOOL)animated
{ [self AdaptLabels];
NSLog(#"View will appear.");
}
Every time a new tab is chosen, it updates the labels in the new View, according to a global variable set by the Menu, just before they appear. Very quick and clean. Thanks to all of you!
I started a new project with iOS 6 ARC and Storyboards
I made a very simple app that has a Tabbar and 2 views
so now I created a TestViewController file with is extending UITabBarController and I put the custom class in the storyboard.
now the issue is that I am trying to implement some delegate methods like
- (BOOL) tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController;
But it never calls it. Can anyone help?
I noticed too that if I put that code in the first view controller it works fine. It seems like the first view controller overwrites the TabBarController before. I am very confused.
for more testing I added in the TestViewController.m some logging:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#",self.tabBarController.viewControllers);
}
and the view controllers are null.
I even tried doing self.tabBarController.delegate = self;
But still no solution.
TestViewController is your tab bar controller, so your log should just be self.viewControllers, not self.tabBarController.viewControllers. You shouldn't need to add the property viewControllers either, since your subclass inherits that property from UITabBarController. The reason your delegate message is not called is because of the same problem. You should set the delegate with (in TestViewController):
self.delegate = self;
This is assuming that you want TestViewController to be the delegate, it wasn't clear to me if that's what you wanted.
Have you tried linking them in Interface Builder?
Add this to your header file first though
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
I am trying to find a way to make an item of the TabBar acting as a "UIbutton".
I would like when pressing to this item just make it work as a ibaction method.
I tried several implementation as :
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item{
}
But I was not able to get the method working.
What will be the best solution to fake an item function of a tabbar, and make it open an UIActionSheet for example ?
Try using an IBOutlet and UITabBarDelegate in your viewController.
#interface MyViewController : UIViewController <UITabBarDelegate> {
IBOutlet UITabBar* tabBar;
}
#end
Connect the UITabBar to that IBOutlet in Interface Builder.
Set the delegate to 'self' in your viewController's viewDidLoad method:
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
tabBar.delegate = self;
}
And set up the delegate method with some way to differentiate the tabs:
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
NSLog(item.title);
if([item.title isEqualToString:#"some label"]) {
// do something for this specific button
}
}
(This is an old post, but I had the same question. Hopefully this saves someone else the same trouble.)
You can try the tabBarController shouldSelectViewController delegate method. Override this. Return NO on the tab you want to display an ActionSheet from, and instead instantiate the ActionSheet in this method.
You'll be required to have a placeholder UIViewController in place of this tab.
As mentioned above, this goes against Apple HIG and might be reason for your app to be rejected.
Check this out! These people create a tabBar with a uibutton in it! http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/
Full source code:
https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar
I tried the code some time ago and it worked for me.
Call your action method in the viewDidLoad method of the view of the tab bar item selected.