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.
Related
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 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.
I have a Tab Bar Controller with four navigation controllers added to it. The navigation controllers appear as Tab Bar Items in the Tab Bar Controller. Now I want to add a fifth button to the tab bar, that does not open another view, but triggers some custom code. I want to display an overlaying "share menu" when clicking that Tab Bar Item regardless on which of the four pages the user is. How can I do that?
I can suggest to add dummy UIViewController to the last index and handle UITabBarControllerDelegate
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
if ([viewController == ...your dummy view controller...]) {
//Your custom action
return NO;
}
return YES;
}
Krivoblotsky has given the right answer! I'd like to elaborate a little more for anyone who is confused because for the full implementation there are a couple more moving parts. Let's say you have the app below. As it is when you click the home or profile icon the respective view will display. Let's say instead of the profile view to display, you want to add your custom transition / behavior.
To do this:
1. Given ProfileViewController class, you want include the UITabBarControllerDelegate in your ProfileViewController
#interface ProfileViewController : ViewController <UITabBarControllerDelegate> #end
2. Access your tabBarcontroller's delegate and set this as yourself in your ProfileViewController.m's viewDidLoad
self.tabBarController.delegate = self;
Essentially what this does is say hey, you know the tabBarController's delegate? (The guy that handles events) I know a guy and let this guy (self) handle those events instead. Like in English, you DELEGATE work to other people (you are the delegating object). The thing that handles the work, is the DELEGATE.
3. Implement the custom needed behavior
-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:
if ([viewController isKindOfClass:[ProfileViewController class]]){
NSLog(#"It's a profile");
return NO };
};
else{ return YES; }
The NO return says, when ProfileViewController is selected, do not do default behavior and display it's view.
Excellent explanation of delegates
In Storyboard, add a UIVIewController and connect it to the tab button you want to perform your custom action.
Give that UIViewController a unique title. e.g. "for custom action". It really doesn't matter, as nobody will ever see that title. It is just for you to use in the code below to identify that tab was tapped.
Create the class below and assign it to your UITabBarController in Storyboard
class TabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
delegate = self
}
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
if viewController.title == "for custom action" {
//do your custom actions
return false
}
return true
}
}
You should simply implement the following UITabBarDelegate method:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
I have 2 versions of a tabbed ios5 application, one created using a storyboard and one using xib files. The storyboard version does not call the UITabBarControllerDelegate method didSelectViewController (the xib version does). Something is (I think) missing from the storyboard, but I don't know what. Another way of framing the question might be — how can I refer to the UITabBarController object instantiated by the storyboard?
Thanks for your help.
EDIT: The tab bar controller delegate is set:
In AppDelegate.h:
#interface MyAppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>
#property (strong, nonatomic) UITabBarController *tabBarController;
In AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.tabBarController.delegate = self;
return YES;
}
Then later in AppDelegate.m, the delegate method is:
- (void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"Got Here");
}
The NSLog output never appears. The problem seems to me to be that I am not correctly referencing the tab bar controller object which has been instantiated by the storyboard.
How do I do that?
I had this issue.
If you're not using storyboards, setting the UITabBarController delegate in the AppDelegate is the way to go. However, with Storyboards, the AppDelegate has no idea where the tabBarController is on startup. You'd think by subclassing the tabBarController and adding the delegate method:
(void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController {
}
... would be enough. But, it's irritatingly not.
I needed to know when a user had pressed a tab button. I needed to know this more that I needed to know that the viewController's "- (void)viewWillDisappear:(BOOL)animated {}
" method had been run.
I decided to make my UITabBarController a delegate of itself. This seemed silly to me but I did the following...
#import <UIKit/UIKit.h>
#interface PlumbsTabBarController : UITabBarController <UITabBarControllerDelegate>
#end
And then, in my viewDidLoad method, wrote the following:
[self setDelegate:self];
Which enabled my tab bar delegate methods to run.
Crazy or what?
Ok - I'm editing this answer now, as even though the above is all correct, where a navigationController is being used, selected with each tabBarButton touched, the didSelectViewController delegate method will, when you try to NSLog(#"%#", viewController); only show you that you have selected the UINavigationController class?
So, the total solution, just to add more complexity, is to subclass the UINavigationController for each viewController that you want to monitor, (do something) when the tabBarbutton has been touched.
It works for me anyhow. And, if anyone can nit-pick through the above dribble, they might find an aspect that's useful - and that's enough for me - seeing as I find this site utterly useful too.
Put [self setDelegate:self]; in your ViewDidLoad or somewhere where the object get's initialized