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.
Related
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?
I have the following storyboard in an application I am working on:
At the root, I have a Tab Bar Controller. It links to two View Controllers.
The first View Controller to display a newsfeed with pictures uploaded by the user (the one at the bottom in the storyboard).
The second View Controller serves to initiate the taking of a picture and attach some data to it. In the last step (top right), when touching "Save" in the right item of the Navigation bar, I want the user to be redirected to the newsfeed View Controller passing it some data.
I tried using a segue and it works. The data are passed to the newsfeed but the wrong tab is selected. I changed the selected tab using
[self.tabBarController setSelectedIndex:0];
But by tapping on the second tab again, things are messed up. I can see the newsfeed instead of the taking a picture screen. If I tap again, it crashes.
At some point I thought I may have got the wrong storyboard and should have implemented a TabBar in my newsfeed and handle the taking picture as a modal view.
Would you know any clean way to achieve this?
Thanks
You should not use a normal segue, which adds the destination controller to the stack. To do what you are trying to the best way should be to use an unwind segue. This is a rough sketch of what you need to do:
• Declare an unwind segue action in the NewsfeedController like (IBAction)unwindFromPictureSaved:(UIStoryboardSegue *)segue;
• Connect your "Save" button in your SavingPictureController to the "Exit" icon in the storyboard and select the previously defined method;
• In the newly created unwind segue define its identifier with something like SavedPictureSegue;
• Define the data to be passed in SavingPictureController's header with something like #property (strong, readonly, nonatomic) id passedData;
• In SavingPictureController implement
-(void)prepareForSegue:(UIStoryboardSegue *)segue
{
if ([segue.identifier isEqualToString:#"SavedPictureSegue"]) {
_passedData = // Your data here
}
}
• In NewsfeedController now implement the previously defined method and fetch the data from (SavingPictureController *)segue.sourceController. Be sure to #import "SavingPictureController.h".
Thanks to #Davide, I created a subclass of TabBarController and implemented the method below:
// Find the appropriate controller to answer to an unwind segue
// For each child view controller
// Checks if it is a Navigation Controller
// If it is check its children view controllers
// Return the first view controller that answers the unwind segue
// This because I assumed the default behavior is just to check one level up (in this case, it would have stopped at the NavigationController)
// Based on https://developer.apple.com/library/ios/technotes/tn2298/_index.html#//apple_ref/doc/uid/DTS40013591-CH1-CCVC-SELECTING_A_CHILD_VIEW_CONTROLLER_TO_HANDLE_AN_UNWIND_ACTION
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
BOOL resChildren, res;
for(UIViewController *controller in self.childViewControllers) {
if ([controller isKindOfClass:[UINavigationController class]]) {
for (UIViewController *childController in controller.childViewControllers) {
resChildren = [childController canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
if (resChildren) {
return childController;
}
}
}
res = [controller canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
if (res) {
return controller;
}
}
return nil;
}
Then in the unwind method of the 'NewsFeedController" it is necessary to set the correct index to see the controller with something like:
[self.tabBarController setSelectedIndex:1];
I uploaded a demo on github at https://github.com/kintso/unwindSegueWithTabBarControllerAndNavigationController
In my app, I need to go to another UIViewController with a button click, but when I did it in the new UIViewController it displays only what I set programmatically.
I used:
NewSubject *NewS = [[NewSubject alloc] initWithNibName:nil bundle:nil];
[self presentViewController:NewS animated:YES completion:nil];
"NewSubject" is the UIViewController I need to go too, however I want the computer to display also the stuff I set by the Storyboard.
Have you set in the Storyboard, in the NewSubject View Controller, in the third tab (Show Identity Inspector) the StoryBoard ID?
You should set it to some name, such as "NewSubject" and use it as follow:
NewSubject *NewS = [self.storyboard instantiateViewControllerWithIdentifier:#"NewSubject"];
[self.navigationController pushViewController:NewS animated:YES];
I want the computer to display also the stuff I set by the Storyboard.
If you're using a storyboard, -initWithNibName:bundle: is the wrong method to use. You can use UIStoryboard's -instantiateViewControllerWithIdentifier: method to create a new view controller that's defined in a storyboard, but the more typical approach is to have your button trigger a segue between the two view controllers.
Try this:
While editing your storyboard, control-drag from your button to the new view controller. A popup menu should appear that lets you choose how you want to transition between the view controllers -- push (push the new controller onto the top of the navigation stack), modal (present the view controller modally), etc. Pick the appropriate one.
In simple cases, you're done -- there's no need to write any code just to get the transition to happen. The segue takes care of creating the new view controller and performing the transition for you. However, you often want to pass some data from the existing view controller to the new one. If that's the case, implement -prepareForSegue:sender: in the existing view controller -- this method gives you a chance to pass whatever data you need. It'll look something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// It doesn't hurt to check that it's the segue that you expect
if ([segue.identifier isEqualToString:#"MySegueIdentifier"]) {
NewViewController *newVC = segue.destinationViewController;
// This is your chance to set properties or call methods to pass data to the new view controller
newVC.foo = self.foo;
newVC.bar = self.bar;
}
}
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.
Hi there, Now I'm trying to create a Pop-OverView using an Xcode
storyboard. Firstly, I have
rootViewController, UIViewController, and UITableViewController
I want the UIView to act as a page flip and the UITableView will show popOver under the navigationBar item controller.
For the UITableView, I want to make a Pop-Over under NavigationBar controller. The problem is, when I touch the Navigation item to show the UITableViewController, it shows correctly, but when I try to close the Pop-Over View, it won't close. And then, the navigation item doesn't work well. It shows multiple instances of popOverView when I touch it multiple times.
This doesn't seem to make sense to me. Can anyone help me out or tell me where to find documentation / tutorials on this?
UPDATE:
For the UIPopOverController, it seems to work well now, but it is still bugging me when I touch a Navigation Item multiple times. It will show multiple instances of PopOver. How can I handle it, so it will show only one instance?
I had the same problem and mostly found the solution here. Basically you change the action of the button each time it's pressed to either display or dismiss the popover. Here's the code I ended up with:
#interface FilterTableViewController : UITableViewController {
UIPopoverController *editPopover;
id saveEditSender;
id saveEditTarget;
SEL saveEditAction;
}
-(void)prepareForSegue:(UIStoryboardPopoverSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"EditFilterSegue"]){
// Save the edit button's info so we can restore it
saveEditAction = [sender action];
saveEditTarget = [sender target];
saveEditSender = sender;
// Change the edit button's target to us, and its action to dismiss the popover
[sender setAction:#selector(dismissPopover:)];
[sender setTarget:self];
// Save the popover controller and set ourselves as the its delegate so we can
// restore the button action when this popover is dismissed (this happens when the popover
// is dismissed by tapping outside the view, not by tapping the edit button again)
editPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
editPopover.delegate = (id <UIPopoverControllerDelegate>)self;
}
}
-(void)dismissPopover:(id)sender
{
// Restore the buttons actions before we dismiss the popover
[saveEditSender setAction:saveEditAction];
[saveEditSender setTarget:saveEditTarget];
[editPopover dismissPopoverAnimated:YES];
}
-(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
// A tap occurred outside of the popover.
// Restore the button actions before its dismissed.
[saveEditSender setAction:saveEditAction];
[saveEditSender setTarget:saveEditTarget];
return YES;
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Before we navigate away from this view (the back button was pressed)
// remove the edit popover (if it exists).
[self dismissPopover:saveEditSender];
}