How to use Storyboard to make popover that can be used in code? - xcode

I'm building a collection of forms each of which contains several fields. Some of the fields are UITextFields that will display a date. I've created a new class called DatePickerTextField, a descendant of UITextField. When a DatePickerTextField is tapped I'd like for a UIDatePicker control to appear in a popover.
My question is how do I use the storyboard to implement the popover? I can do a segue when there is a specific, visible control in the scene. But how do I represent a generic popover in the scene that I can attach to any instantiated DatePickerTextField that becomes active?

You can create segue that is not connected to any control but I don't think that there would be way to specify anchor point for popover from code. Another option is to create ViewController that is not connected with any segue. When editing storyboard, create ViewController which will be placed in popover, select it and navigate to Utilities pane->Attributes Inspector. Set Size to Freeform, Status Bar to None, specify unique Identifier that will be used to instantiate ViewController from code. Now you can change the size of ViewController by selecting its View and navigating to Utilities pane->Size Inspector.
After that you can create popover from code:
- (IBAction)buttonPressed:(id)sender {
UIView *anchor = sender;
UIViewController *viewControllerForPopover =
[self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
popover = [[UIPopoverController alloc]
initWithContentViewController:viewControllerForPopover];
[popover presentPopoverFromRect:anchor.frame
inView:anchor.superview
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
One caveat is that you need to hold reference to popover as ivar of your class, otherwise it'll crash because UIPopoverController would be released and deallocated after buttonPressed returns:
#interface MyViewController : UIViewController {
// ...
UIPopoverController *popover;
// ...
}

So, I had a similar issue, and in case others might benefit, I figured I'd share it, since I benefit so much from stackoverflow.
This solution allows you to set the anchor of a customizable popover segue. It also allows you to configure the segue to be modal or not (I could not find a way to prevent the segue by dimming the exterior context, so if someone knows how to do that, I would be interested in hearing it); this is accomplished by setting the passthrough views for the popover controller. I also added the capacity to specify a custom view, rather than the view of the source viewcontroller (since I needed this capacity); this portion is not critical to the solution.
DynamicPopoverSegue.h
#interface DynamicPopoverSegue : UIStoryboardPopoverSegue
#property BOOL isModal;
#property UIView* sourceView;
#property CGRect anchor;
#end
DynamicPopoverSegue.m
#implementation DynamicPopoverSegue
- (void)perform
{
if (!self.popoverController.popoverVisible)
{
UIViewController* dst = (UIViewController*)self.destinationViewController;
UIViewController* src = (UIViewController*)self.sourceViewController;
UIView* inView = _sourceView ? _sourceView : src.view;
self.popoverController.contentViewController = dst;
if (!_isModal)
{
[self.popoverController setPassthroughViews:[[NSArray alloc] initWithObjects:inView, nil]];
}
[self.popoverController presentPopoverFromRect:_anchor
inView:inView
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
}
#end
Then you just set your segue to "Custom" in the storyboard, and set the segue class to "DynamicPopoverSegue". In my case, since I wanted to associate it with dynamic layers in a view, I could not set the anchor, so I created the segue by control clicking from the view controller icon in the bar beneath my view controller to the view controller I was using to present the popupover.
To call the popover segue:
[self performSegueWithIdentifier:#"MyPopoverSegue" sender:self];
And to configure the popover segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"MyPopoverSegue"])
{
DynamicPopoverSegue* popoverSegue = (DynamicPopoverSegue*)segue;
// set the anchor to wherever you want it to be
popoverSegue.anchor = _destinationFrame;
}
}

- (IBAction)pressItemChooseOprateRoom:(id)sender {
if (isPad){
// UIView *anchor = sender;
UIViewController *viewControllerForPopover =
[self.storyboard instantiateViewControllerWithIdentifier:#"OperateRoomList"];
_myPopover = [[UIPopoverController alloc]
initWithContentViewController:viewControllerForPopover];
CGRect rc=[self getBarItemRc:sender];
[_myPopover presentPopoverFromRect:rc
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[MLControl shared].popover =self;
// [self perfformSegueWithIdentifier:SEGUE_POP_OPERATEROOM sender:self];
}else{
[self iphoneOpenOperateRoomList];
/* [self performSegueWithIdentifier:#"iPhonePushOperateRoom" sender:self];
*/
}
}
-(void)iphoneOpenOperateRoomList{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"OperateRoomList"];
// if (!index.showTabBar) {
// vc.hidesBottomBarWhenPushed = YES;
// }
[self.navigationController pushViewController:vc animated:YES];
}

Just used the answer from Jonnywho for my SWIFT project. In case you need it:
Here's the SWIFT version:
let anchor: UIView = sender
var viewControllerForPopover = self.storyboard?.instantiateViewControllerWithIdentifier("GameAboutViewController") as! UIViewController?
let popover = UIPopoverController(contentViewController: viewControllerForPopover!)
popover.presentPopoverFromRect(anchor.frame, inView: anchor, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)

Add a UIView in the scene dock.
You can add it as a subview to any existing view on the view controller.
You can then toggle it's isHidden property as you require.
You can add multiple such subviews and create many such popups.
This technique will save you from setting up a new View Controller and using segues.

Related

how to add View controller to every item on a menu?

i'm sure it's pretty easy , but i'm spending hours to get it right .
I download this simple menu from github :
https://github.com/Antondomashnev/ADDropDownMenuView
the view controller looks like this :
- (void)addDropDownMenu{
ADDropDownMenuView *dropDownMenuView = [[ADDropDownMenuView alloc] initAtOrigin:CGPointMake(0, 20)
withItemsViews:#[[self dropDownItemWithTitle:NSLocalizedString(#"Item 1", #"")],
[self dropDownItemWithTitle:NSLocalizedString(#"Item 2", #"")],
[self dropDownItemWithTitle:NSLocalizedString(#"Item 3", #"")]]];
dropDownMenuView.delegate = self;
dropDownMenuView.separatorColor = [UIColor blackColor];
[self.view addSubview: dropDownMenuView];}
i'm adding 2 more view controllers to the storyboard.
how can I connect them with Item 2 and Item 3 ? ( so I will see a different View every time i'll click different item ) .
any help will be appreciated...
I've changed demo code to show you solution.
In ViewController.m file add private category with two properties
#interface ViewController ()<ADDropDownMenuDelegate>
#property (nonatomic, strong) NSArray *viewControllers;
#property (nonatomic, strong) ADDropDownMenuView *dropDownMenuView;
#end
Then you need to create set viewControllers array. For example i want to create two instances of ViewController2 class (clean UIViewController template) in viewDidLoad
ViewController2 *vc1 = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2Blue"];
[self addChildViewController:vc1];
ViewController2 *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2Yellow"];
[self addChildViewController:vc2];
self.viewControllers = #[vc1, vc2];
You have to add these view controllers as a child view controller to self. Don't forget about setting storyboardID for your view controllers in storyboard. In this case first view controller has ViewController2Blue storyboardID and second has ViewController2Yellow.
And the last thing to do is implementing ADDropDownMenuDelegate method
- (void)ADDropDownMenu:(ADDropDownMenuView *)view didSelectItem:(ADDropDownMenuItemView *)item
{
NSLog(#"%# selected", item.titleLabel.text);
for(UIViewController *viewController in self.viewControllers){
[viewController.view removeFromSuperview];
}
if([item.titleLabel.text isEqualToString:NSLocalizedString(#"Item 1", #"")]){
[self.view insertSubview:((ViewController2 *)self.viewControllers[0]).view belowSubview:self.dropDownMenuView];
}
else{
[self.view insertSubview:((ViewController2 *)self.viewControllers[1]).view belowSubview:self.dropDownMenuView];
}
}
In this method you remove all UIViewController's views from superview. And then according ADDropDownMenuItemView titleLabel text you add viewController's view to self view.

How do I change a UIButtons label, label color etc. from another view controller?

In one view (main view) controller I have a UIButton that creates a new UIButton. When you make a long press on the new UIButton a new view controller (second view) is presented by presentmodalviewcontroller. In the second view I have a UITableView and in the first UITableViewCell there's a UITextField. What I want is that when you input something in the UITextField the new UIButtons title changes to that.
What I have done is to create a NSString in my app delegate. In the second view in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
I have used this code:
// Passing the TextFieldText to NewButton.
iAppAppDelegate *AppDelegate = (iAppAppDelegate *)[[UIApplication sharedApplication] delegate];
AppDelegate.ButtonText = [TextFieldText text];
iAppView = [[iAppViewController alloc] initWithNibName:#"iAppViewController" bundle:nil];
[TextFieldText addTarget:iAppView action:#selector(ApplyAllObjectsSettings) forControlEvents:UIControlEventEditingChanged];
In the main view I used this action to change the new UIButtons title:
- (void)ApplyAllObjectsSettings {
iAppAppDelegate *AppDelegate = (iAppAppDelegate *)[[UIApplication sharedApplication] delegate];
[NewButton setTitle:AppDelegate.ButtonText forState:UIControlStateNormal]; }
It does however not work. Any idea of how to make this work or another way to do it, would really be appreciated :)
Thanks in advance :)
Update:
In my second views .h file I have referred to the first view controller like this:
#class iAppViewController;
#interface ButtonSettings : UIViewController < UIPickerViewDataSource, UIPickerViewDelegate > {
// iAppViewController
iAppViewController *iAppView;
in the .m file I have imported the first view controller
#import "iAppViewController.h"
And this is the code I use to call the action:
[TextFieldText addTarget:iAppView action:#selector(ApplyAllObjectsSettings:) forControlEvents:UIControlEventEditingChanged];
And this is the action in the first view controller:
- (void)ApplyAllObjectsSettings:(id)sender {
[NewButton setTitle:((UITextField *)sender).text forState:UIControlStateNormal];
}
Your code isn't working because you never actually pass the new text to the button. When you say
AppDelegate.ButtonText = [TextFieldText text];
is set's the ButtonText (which I guess is an NSString) to the UITextFields current text, which is most likely empty. If you look at the docs or other examples, you will see that the selector for UIControlEventEditingChanged actually accepts one argument. This is the sender, so in your case, the UITextField which fires the event. Using it, you can access the entered text and you won't even need your ButtonText variable.
So change row where you set UITextViews target to this: (Notice the new ':')
[TextFieldText addTarget:iAppView action:#selector(ApplyAllObjectsSettings:) forControlEvents:UIControlEventEditingChanged];
Then change your listener to this
- (void)ApplyAllObjectsSettings:(id)sender {
[NewButton setTitle:((UITextField *)sender).text forState:UIControlStateNormal];
}
Update:
So as I said, the iAppView in your second view needs to point to the first view. One way of archiving this is by making it a property like this (in your ButtonSettings.h):
#interface ButtonSettings : UIViewController < UIPickerViewDataSource, UIPickerViewDelegate > {
...
iAppViewController *iAppView;
}
#property (nonatomic, strong) iAppViewController * iAppView;
And don't forget #synthesize iAppView; in your ButtonSettings.m file. Now, when you are creating the instance of ButtonSettings in your FIRST view, you can just pass the reference like this:
myButtonSettingsInstance.iAppView = self;

IOS: use navigation controller in a subview

In a view of my program I have a button and with this button I open a subview; this subview is a view with a tableview. I want go to another view when I push a row of the tableview so I want to make this with a navigation controller; how can I do this?
Your table view delegate will receive a tableView:didSelectRowAtIndexPath: message when you click on one of the table's rows.
You can put there your code to create the UINavigationController and push on to it your new view.
This sample code (from another answer of mine on S.O.) shows how you can do that:
UINavigationController* navigation = [[UINavigationController alloc] init];
iVkViewController *overviewViewController = [[iVkViewController alloc] init];
overviewViewController.title = #"First";
[navigation pushViewController:overviewViewController animated:NO];
This should help you getting things on track.
One side note: you might think of having a navigation controller from the very start, this would make your UI more "well-behaved", but this depends ultimately on your app requirements.
If UIViewController addSubView a view of UITableViewController,you want to push in the method of tableView:didSelectRowAtIndexPath,you should check if self.navigationController is nil. If it's nil,You probably should use
[self.parentViewController.navigationController pushViewController:controller animated:YES];
if self.parentViewController is also nil,Sometimes,you have to set a #property to point out the parentViewController In UITableViewController,like:
#property (nonatomic, weak) UIViewController *parentVC;
and in UIViewController:
UITableViewController *tableViewVC = [[UITableViewController alloc] init];
tableViewVC.parentVC = self;
In UITableViewController ,-tableView:didSelectRowAtIndexPath:
[self.parentVC.navigationController pushViewController:controller animated:YES];

UITabBarController + UINavigationController problem xcode project

I have a problem, I have created a project window based application in xcode, then I create a UITabBarController that manages two views all programmatically, the second view is a tableView and I want to see in the top a UINavigationController, I have tried a lot but I don't know how to have a UINavigationController in the second view. this is the code:
ProjectAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Creo una tabBarController
UITabBarController *tabBarController = [[UITabBarController alloc] init];
//Create the two view controllers
UIViewController *vc1 = [[Visuale1ViewController alloc] init];
UIViewController *vc2 = [[Visuale2ViewController alloc] init];
//Make an array containing the two view controllers
NSArray *viewControllers = [NSArray arrayWithObjects:vc1, vc2, nil];
//The viewControllers array retains vc1 and vc2, we can release
//our ownership of them in this method
[vc1 release];
[vc2 release];
//Attach them to the tab bar controller
[tabBarController setViewControllers:viewControllers];
//Setto la tabBarController come rootViewController di window
[window setRootViewController:tabBarController];
//The window retain tabBarController, possiamo lasciare il nostro riferimento
[tabBarController release];
[self.window makeKeyAndVisible];
return YES;
}
Visuale1ViewController.h
#implementation Visuale1ViewController
- (id)init{
[super initWithNibName:#"Visuale1ViewController" bundle:nil];
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a label
[tbi setTitle:#"Visuale 1"];
return self;
}
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle {
return [self init];
}
Visuale2ViewController.h
#implementation AnswerViewController
- (id)init{
//Call the superclass's designated initializer
/*[super initWithNibName:nil
bundle:nil];*/
[super initWithStyle:UITableViewStyleGrouped];
answers = [[NSMutableArray alloc] init];
for (int i = 0; i<10 ; i++) {
[answers addObject:[Answer DefaultAnswer]];
}
//Get the tab bar item
UITabBarItem *tbi = [self tabBarItem];
//Give it a laber
[tbi setTitle:#"Visuale 2"];
return self;
}
- (id)initWithStyle:(UITableViewStyle)style{
return [self init];
}
//All below are all methods to work the table view, and all go well, the only problem it's the UINavigationController, to manage then the detail of the table...
Now I want to know how I can put a UINavigationController in the second view. I try do this, in ProjectAppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Creo una tabBarController
UITabBarController *tabBarController = [[UITabBarController alloc] init];
//Create the two view controllers
UIViewController *vc1 = [[Visuale1ViewController alloc] init];
UIViewController *vc2 = [[Visuale2ViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:vc2];
//Make an array containing the two view controllers
NSArray *viewControllers = [NSArray arrayWithObjects:vc1, navController, nil];
//The viewControllers array retains vc1 and vc2, we can release
//our ownership of them in this method
[vc1 release];
[vc2 release];
//Attach them to the tab bar controller
[tabBarController setViewControllers:viewControllers];
//Setto la tabBarController come rootViewController di window
[window setRootViewController:tabBarController];
}
In this way I can visualize the NavigationBar, but I lost the name of the SecondTabBar. Sorry for my english, how I can do this?
Yes in the second view you have to set title as
[self.navigationItem setTitle:#"Visuale2"];
For TabBar title-
UITabBar *tabBar = [self.tabBarController tabBar];
NSArray *tabBarItems = [tabBar items];
UITabBarItem *secondTabBarItem = [tabBarItems objectAtIndex:1];
[secondTabBarItem setTitle:#"Visuale2"];
I left the code as it was and I added in init Visale2ViewController this:
UIImage *i = [UIImage imageNamed:#"Hypno.png"];
[tbi setImage:i];
and now in can see the text Visuale2 in tabBar and the image...i don't know why...
You need to set the tabBarItem property for your UINavigationController. Something like this.
UITabBarItem *tabItem = [[UITabBarItem alloc] initWithTitle:#"Visuale 2" image:nil tag:1];
UIViewController *vc2 = [[Visuale2ViewController alloc] init];
navController = [[UINavigationController alloc] initWithRootViewController:vc2];
navController.tabBarItem = tabItem;
After looking at it,the scenario seems to be same like me.What I faced for the first time when doing Tab+Navigation.
I am sure that there is some problem with your Tab+Navigation based application. Although it shows the Tab as well as navigation are not able to navigate the basic flow.And it is very difficult to solve your problem with such less code.
Instead of this, I had an alternate solution for the same:
Once you have a tab bar in a XIB, the easiest way to approach this is to drag a UINavigationController object over from the Library window (looks like a left nav bar button on a gold background) into the Tree View for your tab bar (the text only view, not the GUI). Place it under the tab bar, then drag your existing view controller under the tab bar controller instead of under the tab bar.
When you go to view that tab you should then see a navigation bar on the top of it... if you are loading the navigation controller from another xib, you'll modify the nav bar in the tab bar xib.
else you can below you can follow the best url for the same:
http://books.google.co.in/books?id=2yYlm_2ktFYC&pg=PA179&lpg=PA179&dq=navigation+with+the+tab+based+application+iphoneSDK&source=bl&ots=nf2YYjX5Am&sig=COpHj9wOtsDChQBglpsljSTsElw&hl=en&ei=3ZoFTeGSOI_tsgbc_Iz6CQ&sa=X&oi=book_result&ct=result&resnum=6&ved=0CDAQ6AEwBQ#v=onepage&q&f=false
http://www.youtube.com/watch?v=LBnPfAtswgw
Hope this will surely solve your problem.

How can I add a UIView as a subview of UIViewController when a button clicked?

In my app I need to add a UIView dynamically whenever user taps on a button in my main UIViewController. How can I do this?
Create a new method in your view controller with this signature: -(IBAction) buttonTapped:(id)sender. Save your file. Go to Interface Builder and connect your button to this method (control-click and drag from your button to the view controller [probably your File's owner] and select the -buttonTapped method).
Then implement the method:
-(IBAction) buttonTapped:(id)sender {
// create a new UIView
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(10,10,100,100)];
// do something, e.g. set the background color to red
newView.backgroundColor = [UIColor redColor];
// add the new view as a subview to an existing one (e.g. self.view)
[self.view addSubview:newView];
// release the newView as -addSubview: will retain it
[newView release];
}

Resources