I have one view with a considerable amount of buttons in it all leading to a new view. I would like to display different data in the new view dependant on what button was pressed to enter it.
A point in the right direction would be awesome.
Connect your buttons to the new view controller using segues. Then you can implement the method prepareForSegue:sender: in the view controller containing your buttons. In that method you can set properties on your new view with whatever data is needed to customize your new view. You'll need to determine which button was clicked. One way of doing that would be to set the tag property of each button to a different value (either in IB or in your code).
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// sender is the button that was clicked
// you could set the tag property of the UIButtons when they are created
// and inspect that property here to determine which was clicked
// vc will be the view controller you are segueing to
YourViewController *vc = [segue destinationViewController];
// set properies of youe next view controller with data needed by new view
switch (sender.tag) {
case 0: // first button
vc.myProperty = someData;
break;
case 1: // second button
vc.myProperty = someOtherData;
break;
etc...
}
}
I guess you need to link your buttons to a function like
- (IBAction) buttonClicked: (UIButton*) sender;
And then depending on what button has been clicked (you can set their tag attributes to differentiate them and them get the sender.tag value to know what button has been click), you just call the corresponding function in your new view to update its data.
Related
Is there a way to summon a callout box on a button next to a textfield or inside the textfield?
Or is UIAlertView my only choice?
Edit: With my successful attempt at creating a UIPopoverController, is there a method to position the arrow so that it does not appear in the center?
I have successfully achieved my goal of creating a callout box as it appears in the image of my question. I'd like to thank Paul Cezanne for mentioning a solution for me to pursue. I guess the name (pop over/callout) is different if it is not displayed in a map view. Anyways, for future apple developers, here are the steps I took that answered my question:
Embed your first view controller with a navigation controller
Keep auto layout and size classes checked in the File Inspector tab on the right hand side in your main storyboard, because the pop over will just act as a push view if we shrink the view controller.
Add a second view controller (you do not need to create a header nor an implementation file)
Drag a button onto the first view controller (you do not need to create an IBAction)
Hold the control key and click and drag from your button on the first view controller to your second controller and the segue choices should appear
Select 'Present As Popover'
Don't forget to create an identifier for the segue
Now heading over to coding, here is the header file of the view controller:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIPopoverPresentationControllerDelegate>
#end
Here is the implementation file of the view controller:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Declare a string to identify the segue
NSString *identifier = segue.identifier;
// If the string matches the string inside #""
if ([identifier isEqualToString:#"popOverSegue"]) {
// Assign the view controller to a pointer
UIViewController *dvc = segue.destinationViewController;
// Identify that the view controller is to be a pop over presentation controller
UIPopoverPresentationController *ppc = dvc.popoverPresentationController;
// Set the size of the view controller
// Width = 200
// Height = 200
dvc.preferredContentSize = CGSizeMake(200, 200);
// Have the pop over presentation controller point upwards
ppc.permittedArrowDirections = UIPopoverArrowDirectionUp;
if (ppc) {
ppc.delegate = self;
}
}
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
Build and Run and you should have a successful pop over controller app. Fin.
I have a an app that has a sidebar menu. My side bar menu has 6 items on it. Items 0-4 will perform segue and move to destination view controller. But item 5 (feedback) when it is tapped should pop up an alert view and not move to another view controller. The solution I thought of is to use shouldPerformSegueWithIdentifier.
Here's what i've got so far:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
BOOL isToDetail = true;
if([identifier isEqualToString:#"FEEDBACK"])
{
isToDetail = false;
}
else
{
isToDetail = true;
}
return isToDetail;
}
Now my concern here is, that everytime it goes thru this code the identifier is always null so it always goes to else instead of the if block. How can I get the identifier?
You should not use a segue to display an alert view because it is not a ViewController.
What you can do is create an IBAction in your code then link the tap event from the "item 5" to the IBAction.
What will happen is that when the button is tapped (usually the event is Touch Up Inside), it will call your IBAction and execute your code. You can find information on the new Alert Views of iOS below:
http://nshipster.com/uialertcontroller/
You have to specify the segue identifier in the Storyboard
Just open your Storyboard, select the segue, and on the Right panel add a unique identifier as showed here
I wanted to know if there's a way to change the Back link in my app.
My app is built like this : The first view (Oil) is a tableView inside a Navigation Controller.
There's 3 button at the bottom, Oil, Property, Application. So if I tap on the first one (Oil) it does'nt change anything as we are already on this view. If I tap on the second button which is Property the view goes on an other Navigation Controller and an other tableView is displayed.
But Now if I tap on a cell in my tableview Property it brings me back to the Oil view. I perform a Segue, and with this segue I set my Navigation Bar Title as the Property name.
PropertyViewController.m :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"PropDetail"]) {
OilViewController *test = segue.destinationViewController;
test.propName = propertyName;
}
}
OilViewController.m :
if (_propName) {
self.title = _propName;
/* Imaginary Code
back.link = PropertyView;
*/
}
else {
self.title = #"
}
This works If I go to Property View and then tap on a property I "go back" to the Oil View and the title is for example Dream. But the problem is that when I click on the Back buttonit brings me back to the Real Oil View. Instead of this I want the back button to go back to the PropertyView.
Can I change that in the code and how ? Thanks. I know I could just duplicate my code, or built my app in an other way, but I'm almost done and I don't want to start from scratch again.
I hope I was clear, Thanks !
You can use unwind segue to back to any view controller you want. Check out this question
What are Unwind segues for and how do you use them?
Well, that question sure sounds weird but i couldn't find a better way to put it.
I m pretty sure its a basic mistake but i m stuck.
I got a main home view controller, there are 2 buttons which leads to 2 different tableViewController.
i will use both of the selections.
But when i get the selected index from one table view and go the the next one, the first one's value become null.
if (tempFromLocationString!=NULL) {
//tempFromLocationString=#"asd";
fromLocationLabel.text=tempFromLocationString;
}
if (tempToLocationString!=NULL) {
toLocationLabel.text=tempToLocationString;
}
this is how i segue from tableView to View controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"fromLocationSegue"])
{
NSLog(#"%#",selectionString);
ViewController *vc = [segue destinationViewController];
vc.tempFromLocationString=selectionString;
}
}
and this is how i get the selected cell's value.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
selectionString=[fromLocationArray objectAtIndex:indexPath.row];
NSLog(#"%#",selectionString);
}
this is my code. i get temp strings with segues and i m applying these codes in view did load.
all the NSStrings declared in .h files.
the flow is like this;
user enter the app,
select a button,
goes to the first table view controller
select a location,
clicks ok button and goes back to the first view controller with segue ( selectionString)
the label is set to the selectionString appropriately
user click next button,
goes to the select table view
select a location
clicks ok and goes back the first view controller now the second label is set to the selectionString appropriately but now the first one is deleted and the string become null
OK
Your app flow
Case1
User enter the app - Correct
Select a button - Correct
Goes to the First TableViewController select a location -
Correct
Clicks ok button - Correct
and Goes back to the first view controller with segue
(selectionString) the label is set to the selectionString
appropriately - Incorrect
Step 5 is incorrect, why?
Answer - Because you are again pushing the ViewController after the selection in tableViewController, where as your ViewController already exist in the stack, so here instead of using segue, you should just pop the viewcontroller with same reference taken from ViewController.
Case2
User click next button - Correct
Goes to the select table view select a location clicks ok - Correct
and goes back the first view controller now the second label is set to the selectionString appropriately but now the first one is deleted and the string become null - Incorrect
Step 3 is incorrect the same way as Case1.
Answer- Again you are actually not going back, you are going forward, so what happens is you are creating a new instance of ViewController on selection, which doesn't have the previous selected value.
Solution
Create NSString property in each respective tableViewController separately same as you have in ViewController.
When you segue tableViewController from ViewController, assign the property like
TableViewController *vc = [segue destinationViewController];
vc.tempFromLocationString=self.tempFromLocationString;
On selection in tableviewcontroller do the following
self.tempFromLocationString=selectionString;
[self.navigationController popViewController:YES];
Now instead of assigning value in ViewDidLoad in ViewController, do it in ViewWillAppear.
I hope it helps.
Maybe your strings are not NULL when you set your labels.
Try to put a breakpoint before those lines, and check your temp strings
if (tempFromLocationString!=NULL) {
//tempFromLocationString=#"asd";
fromLocationLabel.text=tempFromLocationString;
}
if (tempToLocationString!=NULL) {
toLocationLabel.text=tempToLocationString;
}
If they are not NULL try this:
if (tempFromLocationString && [tempFromLocationString length] > 0) {
fromLocationLabel.text=tempFromLocationString;
}
My problem seems like a generic problem, yet can't seem to find an answer for it.
I have a situation where when the user taps on a custom UITableViewCell, I would like to display an alert and then based on the response to the alert, either stay on the same view (user selecting cancel) or display another view (if the user selects proceed). And I would like to do this using the storyboard feature & segues.
How would one go about this? Do you have to do this the old fashioned way?
#user, Just create the alertView the old fashion way; I do know of any storyboard feature to do this differently. Where storyboard can help is with the segues. You can call the segues programmatically. With you alert view cancel button you can just return (i.e. do nothing). For the other option, to display another view, you can programmatically call a segue to transition to the desired view. If you don't have the proper segue already defined for some other reason on your storyboard, just create a button out and use that to create the segue and name it. Name the segue by clicking on it in storyboard and use the attributes inspector to give it name (identifier). Then hide the button or put it out of the view. I typically put these type of button on the toolbar and use spacers to keep them out of the view. Here's some sample code:
Call the segue from the alert view delegate like this:
[self performSegueWithIdentifier: #"done" sender: self];
Also implement this method to do any necessary task to prepare for the segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"done"])
{
// [[segue destinationViewController] setManagedObjectContext:self.managedObjectContext];
// [[segue destinationViewController] setSelectedClient:selectedClient];
}
}
You can create segues directly from the startingViewController to multiple destinationViewControllers that can then be "performed" programmatically. You do not need to create any hidden buttons for them, which does seem like a hack.
OK I came up with a solution in keeping with the storyboard that I like.
Example:
My tableview has 2 sections, grouped, and cells are dynamic prototype. Section 0 contains one row/UITableViewCell & I don't want it to segue. Section 1 contains multiple cells that I want to trigger the segue & drill down into the detail.
In Storyboard:
I removed the segue linking the tableviewcell to the destination view controller.
I made a 'generic' segue linking the source view controller directly to the destination view controller.
In the attributes on the segue, I set the identifier ('EditTimePeriod') and set the type to Push (I presume Modal would work just the same).
In the source view controller:
In the prepareForSegue method I handled both the common 'AddTimePeriod' segue I control-dragged from my UIBarButtonItem (Add), along with the 'generic'(vc-->vc) 'EditTimePeriod' segue.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// handle the click of the 'Add' bar button item
if([segue.identifier isEqualToString:#"AddTimePeriod"]) {
TimePeriodViewController* tpvc = (TimePeriodViewController*)segue.destinationViewController;
tpvc.delegate = self;
// database & entity stuff for adding the new one to the mOC, etc
}
// handle the click of one of the 'editable' cells -
if([segue.identifier isEqualToString:#"EditTimePeriod"]) {
TimePeriodViewController* tpvc = (TimePeriodViewController*)segue.destinationViewController;
tpvc.delegate = self;
TimePeriod * newTP = [self.timePeriodArray objectAtIndex:self.tableView.indexPathForSelectedRow.row];
tpvc.timePeriod = newTP;
}
}
Then I implemented the tableView:didSelectRowAtIndexPath method, and put my condition in here. If the selected row was outside of section zero I called the EditTimePeriod segue manually, defining the sender as the selected tableviewcell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(self.tableView.indexPathForSelectedRow.section!=0){
[self performSegueWithIdentifier:#"EditTimePeriod" sender:[tableView cellForRowAtIndexPath:indexPath]];
}
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
return;
}
would be nice to code the cell in section 0 so that it is not selectable in the first place!
Hope this helps though.
** and then 5 minutes later I took another look and realized I could just move the data from section 0 into the section header, which is more intuitive and wasn't being used anyway. leaving the design open for a standard segue from each tableviewcell without needing any condition/check. Was a good exercise anyway though :)