I have a button which has an action that gives a push to another view. My goal is to make this button to open different views according to the selected segment. For example: I have a button called "Request" and have a control segment with two segments, called "Pizza Salt" and "Sweet Pizza." When selected, for example, "Pizza Salt" in the segment and then immediately click the "Request" button, I want to open a view to the menu of "Salt Pizza.", And selected "Sweet Pizza" I want the button to open another view with the menu of the "Sweet Pizza."
Note: I already have the two controllers ready with views.
What code do I use?
My code:
- (IBAction)changeButtonCode:(id)sender {
if (_firstSegmentSixthView.selectedSegmentIndex == 0);
}
- (IBAction)pushToNextView:(id)sender {
}
Use this method to perform actions on different buttons of UIsegmentControl:
- (IBAction) segmentControlBtnAction:(id)sender
{
UISegmentedControl* segmentControl = (UISegmentedControl *)sender;
int index = [segmentControl selectedSegmentIndex];
switch(index)
{
case 0: // Perform action on first button of segment controller
break;
case 1: // Perform action on second button of segment controller
break;
case 2: // Perform action on second button of segment controller
break;
default
break;
}
}
Connect this method with UISegmentControl from xib, using the attribute "value changed".
Upon pressing the request button:
if (_firstSegmentSixthView.selectedSegmentIndex == 0) //salty
{
ViewController1 *vc1 = [[ViewController1 alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
else if (_firstSegmentSixthView.selectedSegmentIndex == 1) //sweet
{
ViewController2 *vc2 = [[ViewController2 alloc] init];
[self.navigationController pushViewController:vc2 animated:YES];
}
Related
I would like to check what the current rootViewController is.
I have a side menu viewController that slides out from the left of the screen and it displays 4 buttons - each point to a different viewController. When they are tapped, for example button1:
- (IBAction)button1Tapped:(id)sender {
[self.sideMenuViewController setContentViewController:[[UINavigationController alloc] initWithRootViewController:[[myViewController1 alloc] init]]
animated:YES];
[self.sideMenuViewController hideMenuViewController];
}
So I'm trying to do this:
User is on myViewContollerX and opens the sideMenuViewController.
On sideMenuViewController, buttonX is grey because the user was currently on myViewControllerX.
User taps buttonY and myViewControllerY shows.
On sideMenuViewController, buttonY is now grey because the user was currently on myViewControllerY.
So I'd need to check what the current rootViewController is, I assume. How would I do this? Thanks.
How to check your current rootViewController and use it in an if statement :
// Get your current rootViewController
NSLog(#"My current rootViewController is: %#", [[[UIApplication sharedApplication].delegate.window.rootViewController class]);
// Use in an if statement
UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
if ([rootViewController isKindOfClass:[MyViewController class]])
{
NSLog(#"Your rootViewController is MyViewController!!");
}
Not sure which side-panel library you're using, but perhaps you can just do the styling of the buttons when they're tapped. Like this:
- (IBAction)button1Tapped:(UIButton *)sender
{
// .... set the center controller
[self setButtonAsActive:sender];
}
- (void)setButtonAsActive:(UIButton *)activeButton
{
for (UIButton *button in #[self.button1, self.button3, self.button3])
{
if (button == activeButton)
// ... make it highlighted
else
// ... make it not highlighted
}
}
You are using a setter to set contentViewController. Simply use a getter and read it.
e.g.
UIVIewController *contentViewController = self.sideMenuViewController.contentViewController;
NSLog(#"ContentViewController class: %#", [contentViewController class]);
you can check its class using:
if([contentViewController isKindOfClass: [UINavigationController class]])
{
// check nav root and disable button
}
Note:
It sounds like it would be much easier to just disable the button when its clicked and enable all the other buttons, but I'm not sure if you need this info for another reason as well.
I have a UIViewController called 'detailViewController'.
This view controller is accessed through multiple different segues using the push segue.
The problem I am facing is that the back button on the detailViewController takes the user back to the previous view controller (as it should), however I would like the back button to take the user to the masterViewController (the default UIViewController in the app).
How do I do this?
I have tried changing the segue types however that didn't really do anything at all.
Peter
The method you're looking for is UINavigationController's popToRootViewControllerAnimated:
From the documentation: "Pops all the view controllers on the stack except the root view controller and updates the display."
You'll need to create a custom back button. You can't afaik override the back button's functionality.
So something like:
UIButton *myBackButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myBackButton addTarget:self action:#selector(popToRoot:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *myCustomBackButtonItem = [[UIBarButtonItem alloc] initWithCustomView:myBackButton];
[self.navigationItem setLeftBarButtonItem:myCustomBackButtonItem];
and then the implementation of popToRoot: would look like:
- (void)popToRoot:(id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
If the masterViewController you're talking about is the root you can call:
[self.navigationController popToRootViewControllerAnimated:YES];
You can create the back button yourself and call [self.navigationController popToRootViewControllerAnimated:YES]. However, that does require you to create the back button yourself. An alternative option could be to take the current view controller, and remove all of them except the first and current ones:
NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableCopy];
[viewControllers removeObjectsInRange:NSRangeMake(1, [viewControllers count] - 2)];
self.navigationController.viewControllers = viewControllers;
Use the following code in order to go back to main view controller:
[self.navigationController popViewControllerAnimated:YES];
Edit:
Based on the comments, I realize that my code takes you only one step back and may not answer what is asked in this question. Thanks.
I came up with a workaround that looks up in a navigation controller's collection and find the offset between the existing and destination controller using name of destination controller and remove the in-between controller. Not sure if it is close to your need but give it a try:
- (NSArray *)navigateToViewController:(NSString *)destinationControllerName withControllers:(NSArray *)sourceControllers
{
NSMutableArray *controllers = [[NSMutableArray alloc] initWithArray:sourceControllers];
NSInteger sourceControllerIndex = [controllers count] - 1; // Value should be index oriented instead of position oriented.
NSInteger destControllerIndex = 0;
// Find position of destination controller (index oriented)
for (UIViewController *controller in controllers)
{
NSString *controllerName = NSStringFromClass([controller class]);
NSLog(#"class name: %#", controllerName);
if([[controllerName lowercaseString] isEqualToString:[destinationControllerName lowercaseString]])
break;
destControllerIndex +=1;
}
// If desired controller does not exists in the stack, do not proceed.
if (destControllerIndex == sourceControllerIndex)
{
return controllers;
}
// If destination is the same as source do not enter in this block
// If destination and source controllers have zero or no controllers in between do not enter in this block
// If destination and source controllers has few controllers (at least one) in between, go inside this block.
// Here "destControllerIndex + 1" shows, there is at least one controller in between source and destination.
else if(destControllerIndex + 1 < sourceControllerIndex)
{
NSLog(#"controllers in stack: %#", controllers);
// Start from the controller following the source controller in stack and remove it
// till the destination controller arrives
for (NSInteger iterator = sourceControllerIndex - 1; iterator > destControllerIndex; iterator--)
{
UIViewController *cont = [controllers objectAtIndex:iterator];
if(cont) {
[cont release]; cont = nil; }
[controllers removeObjectAtIndex:iterator];
NSLog(#"controllers in stack: %#", controllers);
}
}
return controllers;
}
and define it in some base controller:
-(void) popToViewController:(NSString *)controllerName withNavController:(UINavigationController *)navController
{
// STStatistics refers a singleton class of common functions.
NSArray *mArr = [STStatistics navigateToViewController:controllerName withControllers:navController.viewControllers];
navController.viewControllers = mArr;
// There should be more than one controller in stack to pop.
if([mArr count] > 1)
{
[navController popViewControllerAnimated:YES];
}
}
and here is how called:
[self popToViewController:#"NameOfDestinationControllerInNavStack" withControllers:self.navigationController];
I have a table view controller embedded in a navigation controller. The table cells are all static and selecting any of them will segue to another table view. When segue happened, the navigation bar shows 'Cancel' button for the new view, instead of 'Back' button.
I could add a back button in code like
- (void)viewDidLoad
{
self.navigationItem.backBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonSystemItemCancel
target:nil
action:nil];
self.navigationItem.leftBarButtonItem = self.navigationItem.backBarButtonItem;
}
But then the back button would be a rectangle shape, not the default back button shape which has an angle on the left edge. How to simply change the cancel button to a system back button?
Here is my code for segue from table cell to the next table view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row) {
case 0:
[self performSegueWithIdentifier:#"goToSecondTable" sender:self.tableView];
break;
/* and perform segue for other rows */
default:
break;
}
}
And there is nothing to do inside prepareForSegue.
Here is what the connections inspector showed
And Here is the connections for the 'Bar Button Item - Back'
The system provided back button should be the left bar button item by default without having to do anything (in code or in IB).
Remove the connection to the backBarButton in the Connections inspector. Remove the back bar button from the nav bar in IB. Remove the outlet to the back bar button in your code. Run your app, you should see a back bar button provided for you for free.
Why are you performing a segue in didselectrow instead of just pushing the viewcontroller?
try [self.navigationController pushViewController:YOURVIEWCONTROLLER];
that will make sure you have a back button. Also you must use a segue like that, make sure you are using a push segue to your next controller. It also looks like you created your own back button in the second viewController. You do not need to create one, as one will be created for you with the title of the previous viewcontroller. You can make sure it says back by changing self.title = #"Back" in the previous viewcontroller right before you push it.
Codes:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row) {
case 0:
self.title = #"Back";
[self.navigationController pushViewController:SECONDVC];
break;
/* and perform segue for other rows */
default:
break;
}
}
and in viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.title = #"Whatever you want";
}
Customize the code if don't have default back button not working
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:myBackImage style: UIBarButtonItemStylePlain target:self action:someAction];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
I've got a little problem on navigating through my views.
Here is my configuration :
Ive got 1 Tabbar Controller with 2 relationship segues to 2 simple views embedded inside a navigation controller.
Now i want to navigate from view controller 1 to view controller 3 and i also want to show the correct tab selected inside the tabbar. And if i come from view controller 1, i also want that the back button redirects me the the previous tab. I tried something with a segue connected between that views, but if i do so, it just pushes the view controller onto the navigation stack but not changes the tab. So my question now is, what is the best way of managing this Problem
Screenshot:
Here's a way to do it. But I'm posting this really to illustrate why you shouldn't do it.
I'm using VC2's and VC3's view tag property to pass navigation data around, which has the effect of tightly coupling all three objects.
I override back bar button for the VC1->VC3 context. You lose consistency.
VC3->VC2 provides back animation. VC3->VC1 has no animation as it flips from one tab to another. More inconsistency
VC1->VC3, tap Tab Item 2 transitions to VC2. UI confusion.
Anyway if you still want to do this...
.
ViewController1
Has a "jump to VC3" button, wire up to jumpToVC3:
//ViewController1.m
#import "ViewController1.h"
#implementation ViewController1
- (IBAction)jumpToVC3:(id)sender {
NSArray* viewArray = [[[self.tabBarController viewControllers] objectAtIndex:1] viewControllers];
[[[viewArray lastObject] view] setTag:1];
[self.tabBarController setSelectedIndex:1];
}
#end
"jumptToVC3" switches us to tab 2 and sets the frontmost view's view tag property to 1. IF the frontmost view is VC2, this triggers an immediate segue to VC3. If the frontmost view is VC3, this sets up the back button correctly. If other View Controllers get added to this stack, this navigation will break.
ViewController2
Has a "move to VC3" button, wired to a storyboard segue to VC3 "toVC3"
// ViewController2.m
#import "ViewController2.h"
#import "ViewController3.h"
#implementation ViewController2
//we use the view.tag property as a switch:
//0 = do nothing
//1 = segue to VC3
//2 = go to tab 0
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.view.tag ==1){
[self performSegueWithIdentifier:#"toVC3" sender:self];
} else if (self.view.tag == 2){
[self.tabBarController setSelectedIndex:0];
}
self.view.tag = 0;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (self.view.tag ==1) {
[[segue.destinationViewController view] setTag:1];
} else {
[[segue.destinationViewController view] setTag:0];
}
self.view.tag = 0;
}
- (void) viewWillDisappear:(BOOL)animated
{
self.view.tag = 0;
}
#end
ViewController3
Overrides the back button if it's view.tag is set to 1. If you want both context's back buttons to be consistent, you will need to override for the default behaviour as well. You will not be able to get a standard back button look for this override behaviour.
// ViewController3.m
#import "ViewController3.h"
#implementation ViewController3
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.view.tag == 1) {
self.navigationItem.leftBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"0.0"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(goBack:)];
}
self.view.tag = 0;
}
- (IBAction)goBack:(id)sender {
[[[[self.navigationController viewControllers]
objectAtIndex:0] view] setTag:2];
[self.navigationController popToRootViewControllerAnimated:YES];
}
#end
- (void)createBarButtons
{
UIBarButtonItem *myCheckButton = [[UIBarButtonItem alloc] initWithTitle:#"Check Records" style:UIBarButtonItemStylePlain target:self action:#selector(checkRecordsAction)];
UIBarButtonItem *mySaveButton = [[UIBarButtonItem alloc] initWithTitle:#"Save" style:UIBarButtonItemStylePlain target:self action:#selector(saveAction)];
[mySaveButton setTintColor:[UIColor colorWithRed:34.0/255.0 green:97.0/255.0 blue:221.0/255.0 alpha:1]];
NSArray *myButtonArray = [[NSArray alloc]initWithObjects:mySaveButton, myCheckButton,nil];
self.navigationItem.rightBarButtonItems = myButtonArray;
}
I dont know if this question falls under too localized category. But help me out here.So like you see i have created two bar button items. Save is just saving the data onto CoreData,works just fine. But the check records should launch a new UITableviewcontroller.
- (void)checkRecordsAction
{
NSLog(#"the new stack action");
ITMSyncRecordsTVC *syncRecords = [[ITMSyncRecordsTVC alloc]init];
// [self presentViewController:syncRecords animated:YES completion:^{
// self.navigationController.view.superview.bounds = CGRectMake(0, 0, 250, 250);}];
[self.navigationController pushViewController:syncRecords animated:YES];
}
ITMSyncRecordsTVC is a TableViewController with a "Back" button on it.So when i click the check records it launches a tableview controller but no values in it and it does not show the "Back" bar button i put on it. Until now i have been using segues and storyboards just fine. But how do i launch a new view controller without them i dont know. My first leap into ios is ios6. I am missing something I dont know. So let me know how to call/launch a new TableViewController. In android we had intents that did the trick. Please let me know if you need more information. Thanks...
EDIT: So i edited my checkRecordsAction code.
EDIT :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ITMOrdersVC *ordersVC = [[ITMOrdersVC alloc]init];
NSLog(#"at line 188 %d",indexPath.row);
if(indexPath.row < self.salesOrdersArray.count)
{
ordersVC.salesOrder = [self.salesOrdersArray objectAtIndex:indexPath.row];
NSLog(#"the sales purchase order number is %#",ordersVC.salesOrder.purchaseOrderNumber);
NSLog(#"done - 140");
[self.navigationController pushViewController:ordersVC animated:YES];
}
}
So on selecting a row on ITMSyncRecordsTVC table view controller it does the above. I get a new ITMOrdersVC screen with "Back" bar button at the left and 2 dynamically generated bar buttons.I get the 2 dynamically generated bar buttons but not the back. I thought once i click the row it will "go back" to previous screen to which i am passing the salesOrder object. My next step was to check if i get the salesorder object from the TVC then load it. So basically 2 screens only. First screen (save,check sync records). Second screen click a.) back(go to first screen..do nothing) or b.)click a row in second screen and populate first screen without the bar button.If it is not clear please ask me.
To launch a new table view controller using storyboards, you want to:
Have your main scene embedded in a navigation controller.
You want to have a push segue from the main controller to the second one. So control-drag from the view controller icon (in the bar below the main scene) to the next scene:
It should then look like (note the appearance of the navigation bar in the destination table view):
Then select the segue and give it a "storyboard identifier":
And now, your code to transition to that scene would look like:
The checkRecordsAction:
- (void)checkRecordsAction
{
NSLog(#"the new stack action");
[self performSegueWithIdentifier:#"PushSegue" sender:self];
}
Update:
By the way, in the interest of full disclosure, there's an alternative to the push segue. If you give that next scene, itself, a "storyboard id", you can use the following code (obviously replacing "insertNextScenesStoryboardIdHere" with the identifier you give your next scene:
- (void)checkRecordsAction
{
NSLog(#"the new stack action");
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"insertNextScenesStoryboardIdHere"];
[self.navigationController pushViewController:controller animated:YES];
}
I personally don't like this as much, as your storyboard now has a scene floating out there without any segue, your code now has dictated the nature of the transition between view controllers vs having everything in the storyboard, etc., but it is another approach.