centering a uipopover in iPad - ipad

I would like to create a new keyboard for the iPad.
I have designed a view that has the keys and all the underlying work to fill in a textbox as the user presses the keys, and passes the value back to the calling routine when the user presses the return button.
This all works ok.
Now - I want to create this view as a popover.
I have the basic operations complete (pops up and is dismissed)
But now I need some fine tuning help.
Here are my questions...
1) How do I create a popover window centered on the screen without a UIPopoverArrowDirectionAny selection?
2) Ensure the popover window is the size that I created it with in the XIB file (currently, it resizes and removes some of the rightmost size of the window)
Thanks
tony

To present it with no arrows pass 0 for "permittedArrowDirections":
[popOverController presentPopoverFromRect:rect inView:view permittedArrowDirections:0 animated:YES];
To center it, pass a 1x1 rect located at the center of your view:
CGRect rect = CGRectMake(viewWidth/2, viewHeight/2, 1, 1);
[popOverController presentPopoverFromRect:rect inView:view permittedArrowDirections:0 animated:YES];
Then you have a centered and arrow-free popover.
The bit about removing the arrow could break at any time. They didn't provide a UIPopoverArrowDirectionNone option for a reason, they may choose to throw an exception in the future when 0 is passed, or default to something. Use it at your own risk.

If you are using a UIPopoverController, it will have an arrow. Here are your choices.
UIPopoverArrowDirectionAny
UIPopoverArrowDirectionUp
UIPopoverArrowDirectionDown
UIPopoverArrowDirectionLeft
UIPopoverArrowDirectionRight
As you can see there is no UIPopoverArrowDirectionNone
As for the XIB size, in your ViewDidLoad Method of the implementation file, you can set the following.
self.contentSizeForViewInPopover = CGSizeMake(320.0, 360.0);
You can set the size any way you like for the popover.

I've just been working this one out but wanted to do as much in the storyboard as possible which changes the approach a bit:
1) Select the popover in the storyboard and un-tick Directions Up/Down/Left/Right to get rid of the arrows.
To center it on screen override prepare for segue and do something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIStoryboardPopoverSegue* popover = (UIStoryboardPopoverSegue*)segue;
CGFloat horizontalInset = (self.view.frame.size.width - popover.popoverController.popoverContentSize.width) / (CGFloat)2.0;
CGFloat verticalInset = (self.view.frame.size.height - popover.popoverController.popoverContentSize.height) / (CGFloat)2.0;
popover.popoverController.popoverLayoutMargins =
UIEdgeInsetsMake(
verticalInset,
horizontalInset,
verticalInset,
horizontalInset);
}
In my case I also found that the popover segue's corner radius didn't match my design so I change the background color to clear to sort that out i.e. add this to the above block:
popover.popoverController.backgroundColor = [UIColor clearColor];
2) In the destination controller for the segue find the attribute 'Popover' and tick 'Use Explicit Size' and put the size of you want it to appear in popover mode.

Related

Positioning/Sizing of a UIPopOver without an arrow

I am having trouble with setting the size and position of a UIPopOver without an arrow.
What i am trying to do is to bring up a popover view on the top left of the iPad screen and also have the content size that i have set.
I get different content size for the popover when i use an arrow and when i not. When i use the following code:
CGRect rec = CGRectMake(0, 0, 1, 1);
[self.displayOpPopover presentPopoverFromRect:rec inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
The result is:
and when i do:
[self.displayOpPopover presentPopoverFromRect:rec inView:self.view permittedArrowDirections:0 animated:YES];
The result is :
I have set 'use explicit size' for popovers in the storyboard (which is the size of the view when i have an arrow).
But the view somehow resizes itself when the arrow direction is 0.
Any suggestions as to how should i set the popover to the top left without an arrow.
Thanks !

UITableViewCell frame changes while presenting parent view as modal with UIModalPresentationFormSheet

State of code:
I'm writing my own library for forms in table view (I'm aware of Sensible Cocoa but willing to write my own) and I'm dealing with an issue loosely connected to it.
My form is held by UITableViewController in UITableViewStyleGrouped style. This table view controller is created in a button handler with this code (initialization of form model ommited):
// prepare table view model
_formTableViewController = [[ESCTableViewController alloc] initWithModel:model];
_formTableViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:#selector(cancelBarButtonItemHandler:)];
_formTableViewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit
target:self action:#selector(editBarButtonItemHandler:)];
// prepare navigation controller containing the tableViewController
ESCNavigationController *navigationController = [[ESCNavigationController alloc] initWithRootViewController:_formTableViewController];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
// present navigation view controller
[self presentViewController:navigationController animated:YES completion:nil];
Then, I have UITableViewCell subclassed (as ESCTableViewCell) with style UITableViewCellStyleDefault and each form component is a descendant of ESCTableViewCell using its basic initializer and few properties.
I'm doing my custom rendering like this:
Create my custom field (i.e. UITextField) in initializer of specific cell (ESCTextFieldCell)
prepareForReuse is called by framework on cell reuse, where I remove old observers and invalidate what is needed to invalidate
configWithModel:(Model *)model, where I set properties of the cell, add observers etc.
layoutSubviews is called by framework; meta-code of this process is here:
CGFloat const ESCTextFieldWidthRatio = 0.65f;
CGFloat const ESCFieldHeight = 22.0f;
CGFloat const ESCFieldPadding = 10.0f;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
// call super layout subviews first
[super layoutSubviews];
// count width of the text field, so it would fit with label
// must round() the results to avoid antialiasing on fractional values
CGFloat contentWidth = self.contentView.frame.size.width;
CGFloat contentHeight = self.contentView.frame.size.height;
CGFloat fieldWidth = round((contentWidth - (2 * ESCFieldPadding)) * ESCTextFieldWidthRatio);
CGFloat fieldOriginY = round((contentHeight / 2) - (ESCFieldHeight / 2));
CGFloat labelWidth = contentWidth - fieldWidth - (4 * ESCFieldPadding);
// set textlabel and textfield frames
self.textLabel.frame = CGRectMake(ESCFieldPadding, 0.0f, labelWidth, contentHeight);
self.textField.frame = CGRectMake(labelWidth + (3 * ESCFieldPadding), fieldOriginY, fieldWidth, ESCFieldHeight);
[UIView commitAnimations];
The Problem:
I'm trying to have the UI as clean as possible, being a perfectionist; thus I want to have table view cells animated on entry/leave of edit mode, which works pretty well in current state of code.
The issue is with presenting the modal view itself with this form table view inside. It seems (proven by simulator - slow animations), that when presenting the modal view, frame of the table view is updated (contracted) by (at least) a few pixels, which is causing both modal view translation animation AND table view cell resize animation, which is at the end causing a not-so-smooth animation of that modal view presentation.
What I would like to understand is, why the table view cell is resizing on modal view presentation as I don't like the idea to hack the code to disable animations when presenting the modal view (it can possibly cause lots of other issues later).
Please, does someone know why this is happening, or do you have some other idea how to override it non-hacky way?
Thank you a lot!
PS: I'm using ARC, but I don't think it matters.
PS2: Problem occures on both iPad1 and iOS Simulator for iOS5.
Miroslav, I'm not sure this helps, but I've been fighting the same thing. And I'm sharing this here because I assume others might wonder what's happening.
It's not just the cell, it's the entire tableview bounds that aren't settled until ViewDidAppear is called.
So let's say you want to bring up a 500x500 modal with a UITableViewController, you launch it with presentViewController, you will have all kinds of resizing going on until it's finally resolved in ViewDidAppear. In my case I've seen it through debugging go from 1024 wide to 320 then finally to 500. And it's that width that I need to determine the resulting height of the table view cells.
It all seems like a hack in this case and I'm not sure there is a clean solution though I wish for one. One way in which I'm testing it now, is that the custom table view cells have a "final width" property that they look at (if it's set) when sizing in layoutSubviews. That way the proper height of the cell can be calculated (based on this fixed width) at anytime prior to the tableview being in it's final form.
I've seen the same issue in some original (read Apple) applications on iOS, so I consider it a feature of the system. It seems, the best we can do, is to hide it as much as possible. Actually, nobody except me noticed the behavior, so I think nobody is bothered.
Consider it not an answer, but a closure. If you have some real solution for the problem, please write it here and I'll mark it as an answer.
Set the UITableView layout to delete outside autosizing.

popover shrinks to upper left corner when keyboard appears on iPad

I'm working on an app that has some forms that are contained within a popover. My problem is that when I click on any text entry field and the keyboard appears, the popover shrinks to the upper left hand corner of the screen (0,0) and you can't see the fields you are entering into. When you click the hide keyboard button, the popover returns to its normal size and position.
Is there any way to prevent popover resizing when the keyboard appears?
Here are screen shots in case my description is inadequate.
edit: Here is the code for how the popover is presented on the screen:
(void)displayPopoverForOrientation:(UIInterfaceOrientation)orientation {
if ([Utilities getAppDelegate].menuPopover) {
CGRect rect = CGRectMake(0, 0, 0, 0);
if (orientation == UIInterfaceOrientationLandscapeLeft ||
orientation == UIInterfaceOrientationLandscapeRight) {
if (self.currentPopover == RESERVATIONS_POPOVER) {
rect = CGRectMake(365, 0, 0, 0);
} else if (self.currentPopover == ACCOUNT_POPOVER) {
rect = CGRectMake(600, 0, 0, 0);
} else if (self.currentPopover == RESORTS_POPOVER) {
rect = CGRectMake(0, 0, 0, 0);
}
}
[[Utilities getAppDelegate].menuPopover presentPopoverFromRect:rect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionUp
animated:YES];
}
}
Inside the popover is a separate view controller with the layout setup in a xib.
Feel free to ask any questions, I'm fairly new to iOS and Objective C, but I'm not new to coding so I'll do my best to clarify.
edit 2:
I've found that this only occurs in iOS 5. In older versions of iOS, the popover merely collapses vertically until there is enough room for the keyboard. Any ideas about about why this behavior has changed in iOS 5?
It's not possible to prevent the popover from changing shape when the keyboard appears. According to Apple's UIPopoverController docs:
The size you specify is just the preferred size for the popover’s view. The actual size may be altered to ensure that the popover fits on the screen and does not collide with the keyboard.
IOS will try to move it out of the way, but it may not be possible, depending on where you are presenting it from. For best results, present it from a bar button or from inside a scroll view (UITableView is ok), and design your UI so the popover is not too large (if the popover covers most of the screen, perhaps you should consider a segue to a modal view or similar). I found I needed to draw some diagrams so I could understand the layout better before I could get a solution that worked in all cases.
Actually it is very possible!... This is to do with the auto-Resizing that is ticked by default in IB:
I posted this on an another forum with similar question,.. The solution for me was to:
1) Go into the designer by
2) Opening the XIB ViewController that is causing the problem (i.e. the PopOver one).
3) Click to select it's VIEW.
4) Uncheck "AutoResizeSubviews"
5) When loading the PopOver in code, make sure you do:
6) Your_Popup_Window.popoverContentSize = Your_ViewController.view.bounds.size;
I hope this helps.
Kind Regards
Heider Sati

UIPopoverController Anchor Position

I have a UIPopOverController for which the content controller is a UINavigationController.
I'm resizing the popover size according to the content size of the controller pushed/popped into it. Initally i'm presenting the popover by using the method presentPopoverFromRect:inView:permittedArrowDirections:animated:. The anchor position is pointing at the center of the rect which i passed as an argument. If i push a controller(whose content size is small) into the navigationController , the popover shrinks from the bottom and moves above the rect which i mentioned earlier.
I tried to present the popover everytime(for push/pop) , anchor position remains # same point But the animation gets affected , doesnt looks good.
what needs to be done to make the anchor position remains same irrespective of the change in popover size variation ?
I've encountered the same issue and it seems that calling the presentPopoverFromRect method again will keep the anchor at the same position
e.g.
[self.myPopOver presentPopoverFromRect:rectOrigin inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
Hope it works in your case as well
Change frame after presenting UIPopoverController:
[popupController presentPopoverFromRect:btn.frame inView:self.view permittedArrowDirections:0 animated:YES];
CGRect popupFrame = popupController.contentViewController.view.superview.superview.superview.frame;
popupFrame.origin.y = btn.frame.origin.y + btn.frame.size.height+75;
popupController.contentViewController.view.superview.superview.superview.frame = popupFrame;

How can I have a popover come from a tab instead of a view

I have a tabbar app, and I want a popover to come from one of the tabs. Is there a good/easy way to do this without changing views?
There isn't currently a way to directly (through a supported api call) get the frame of a specific tab bar item. What I do is just show the popup from the left end of the tab bar like this:
CGFloat tabBarHeight = self.tabBarController.tabBar.bounds.size.height;
CGRect rect = CGRectMake(0, 0, tabBarHeight, tabBarHeight);
[popoverController presentPopoverFromRect:rect
inView:self.tabBarController.tabBar
permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
You could try to estimate the position of the tab bar item taking the current orientation into account if you really wanted to and adjust the X coordinate of the rect above.
You could also look through the subviews of the tabbar and find the UITabBarButton object but that's not documented so it's not recommended.

Resources