popover rotation - popover

I created an iPad app and it works fine in landscape and portrait. Except when the app is rotated to landscape the popover is positioned incorrectly. Is there a way to add an if statement like pseudocode:
if in portrait CGRect
use size S1 location L1
else if in landscape CGRect
use size S2 location L2
My code:
UIPopoverController* popover = [[UIPopoverController alloc] initWithContentViewController:TweetFeed];
[popover setDelegate:self];
[popover presentPopoverFromRect:CGRectMake(401, 401, 220, 300) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
[popover setPopoverContentSize:CGSizeMake(320, 150)];

Apple's documentation for UIPopoverController addresses this issue:
If the user rotates the device while a popover is visible, the popover controller hides the popover and then shows it again at the end of the rotation. The popover controller attempts to position the popover appropriately for you but you may have to present it again or hide it altogether in some cases. For example, when displayed from a bar button item, the popover controller automatically adjusts the position (and potentially the size) of the popover to account for changes to the position of the bar button item. However, if you remove the bar button item during the rotation, or if you presented the popover from a target rectangle in a view, the popover controller does not attempt to reposition the popover. In those cases, you must manually hide the popover or present it again from an appropriate new position. You can do this in the didRotateFromInterfaceOrientation: method of the view controller that you used to present the popover.

Related

NSView inside an NSPopover: Converting Coordinates

Context
Let P be an NSPopover and view be an NSView that is a subview contained within P.
What I Need
I want to take the frame of view and convert it to the screen's coordinate system. Normally, you would do that like this:
NSRect frameRelativeToWindow = [self convertRect:self.frame relativeToView:nil];
[self.window convertRectToScreen:frameRelativeToWindow];
However, because view is in an NSPopover, its window property is nil and the above method will return NSZeroRect: [0, 0, 0, 0]
So, how can I get my view's frame in screen coordinates if the view is in an NSPopover?
Notes:
The NSPopover IS onscreen and visible.
The view whose frame I am trying to convert to screen coordinates is not a direct subview of the NSPopover or its contentView. The view in question is actually a custom NSView within an NSTableCellView within an NSTableView within an NSScrollView within an NSClipView. The clipView is a direct subview of the NSPopover's contentView.
In a normal NSWindow, you can take any subview and call [self window] to get the containing NSWindow object. Doing that in a popover, however, returns nil.
The following code assumes, that you have
a NSViewController subclass that manages the popover view
the view controller implements NSPopoverDelegate
As hamstergene pointed out, the popover's window won't be available until it is shown.
When the popoverWillShow: delegate method gets called, your popover view's window should be an instance of _NSPopoverWindow (and not nil).
- (void)popoverWillShow:(NSNotification *)notification
{
NSWindow* popOverWindow = self.view.window;
NSRect popoverRectInScreenCoords = [popOverWindow convertRectToScreen:self.view.frame];
NSLog(#"Popover Rect in Screen Coords:%#", NSStringFromRect(popoverRectInScreenCoords));
}
Update
Bryan (the OP) posted a solution to his problem in the comments.
The issue wasn't NSPopover itself. The actual reason for the nil window for some of his subviews was NSTableView, which releases non-visible NSTableCellViews.
As a workaround he implemented viewDidMoveToWindow in his custom NSTableCellView subclass. When viewDidMoveToWindow: gets called, the table cell view already has a window that can be used to perform coordinate conversion.
Your approach for calculating screen coordinates is correct (just don't forget to convert view's frame coordinates to window's base coordinates first using convertRect:self.frame toView:nil).
The problem is that the window is not created until the popover is displayed. Before that, there is no way to find the view's screen coordinates, because it is not on a screen.
If waiting for display is too late for you, catch popoverWillShow: delegate method (or the corresponding notification), which fires right before displaying the popover when the window is already created and positioned.

Core Animation action transition: how do it right

I make a test project with one view inside of content view of main window. Window have two buttons: appear & disappear. I want animate view appearance when appear button pressed, and animate dissapearance when dissapear button pressed. And I want do this with layer actions.
In other words, I want to make animation every time view added or removed from superview. So, in code I just want to write [parent addSubview:view] or [view removeFromSuperview] and animation should work in that moments. So, Layer Actions seems fits my needs.
Here is app screenshot and source code (XCode 4.6):
Here is what I did to do that:
I create a view that will appear/dissapear and add layer action:
_coloredView = [[ColoredView alloc] initWithFrame:NSMakeRect(0, 0, 200, 200)];
_coloredView.bgColor = [NSColor yellowColor];
_coloredView.wantsLayer = YES;
// making appear transition from left
CATransition *appearTransition = [CATransition animation];
[appearTransition setDuration:2];
[appearTransition setType:kCATransitionPush];
[appearTransition setSubtype:kCATransitionFromLeft];
[_coloredView.layer addAnimation:appearTransition forKey:kCAOnOrderIn];
Then when appear button clicked, I call
[contentView addSubview:self.coloredView];
When disappear clicked, I call:
[self.coloredView removeFromSuperview];
And seems some part of things works. The yellow rectangle appears as it should first time. But, here is list of very strange things:
I should call addAnimation:forKey: every time when button clicked (after view was disappeared), since after first appearing animation will no longer work.
Disappear won't work at all (If I try add code after view initialization or before disappear button pressed)
When I try to add subview through animator, my transition not work - just default fade-in animation shown.
Seems that during movement from left to right some sort of fading works. It's visible when you set duration to bigger value.
Try #"subviews" instead of kCAOnOrderIn

iPad - Section of screen no longer receiving touch events after full screen modal view controller dismissed on iPad

I have toolbar at the top of the (full screen) main view in my iPad. The toolbar has a barButtonItem that when pressed, shows a popover.
In the popover, I have a UIButton that when pressed, tells the delegate (the main view controller) to dismiss the popover and show a full page modal view.
This all works fine.
When I dismiss the modal view, the area of the screen the popover occupied - including the main view and toolbar buttons - is no longer responding to touch events.
This problem corrects itself if I rotate the device and only occurs in Landscape mode.
Any suggestions?
Update: This bug does not happen when running in the Simulator, only on an actual iPad.
The delegate method I have to dismiss the full screen modal view..
- (void)fullScreenViewControllerDidFinish:(FullScreenWebViewController *)fullScreenWebView {
[self dismissViewControllerAnimated:YES completion:^{
[self setFullScreenWVC:nil];
[[self view] setNeedsLayout]; //Does't fix the issue
}];
}
Update:
Using Instruments, I've gotten the iPad to show me how it's laying out subviews. It looks like it thinks the iPad is in Portrait when the modal view is dismissed but the device is obviously in landscape.
I fixed the problem.
I was using
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
instead of
UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
The iPad wasn't getting the right orientation for some reason.
Thanks for your help.
I may be misunderstanding you issue, but I would suggest trying to call "setNeedsLayout" in your main view once the modal view is dismissed. This should trigger the auto resize of your view layout and may resolve the issue if it has not auto resized.
Take a look at this link for more information:
http://developer.apple.com/library/ios/ipad/#documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instm/UIView/setNeedsLayout

Autoresize the root view when device is rotated

I am developing PDF reader. I am facing problem while rotating the simulator. What I am doing is, when view is loaded by the ViewController(i.e. in the loadView), I am creating the UIScrollView which contains UIImageView and UIView of the same size(i.e. size of the PDF page). It is working perfectly in the portrait mode. But when I rotate the simulator in the landscape mode, the view is not autoresized according to device. I have tried
self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
in the viewDidLoad() of the ViewController
But it's not working. I am confused how the above two properties work. I guess these properties will autoresize the UIScrollView to the size of root view in which I am loading UIScrollView. But what should be done to autoresize the main view in which UIScrollView is loaded??
I've experienced the same problem when trying to utilise the auto resizing methods. So, I hope this will help. (P.S. I'm assuming you're creating the UI programmatically and not via IB)
So have you tried this?
Inside your viewcontroller add the following:
// Set the View Controller to fit the whole screen.
-(BOOL)wantsFullScreenLayout{
return YES;
}
Inside the loadView method amend your scrollView to:
// set the initial size of your scrollView object.
[scrollView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
// Set the auto resizing attributes.
[scrollView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
In addition to this you might need to set the autoresizingmask margins for either the UIView or UIImageView depending on the type of layout you require when the device is rotated.
This is late reply... It may help if you didn't Fix it yet.
When you create any app in portraid mode and if you want it to rotate (resize) to landscape mode, you should do it in User Interface Builder or .xib (or in Storyboard iPad or iPhone)file.
So to check or to check rotate in the Simulator:
Go to "USER INTERFACE BUILDER", or ".XIB" (or "Storyboard iPad or iPhone") file.
Then select "UIImageView" and go to "SHOW THE ATTRIBUES INSPECTOR".
In the fourth tab (Attributes Inspector) set the mode to “Aspect Fit”, and in the third tab (Size Inspector) and in the fifth tab (Size Inspector) set the autosizing attributes to the following:
Set the arrows to all directions. Sorry can't load image.
Do the same for "UIView" (3).
Before you move on, you can double check that you’ve gotten all of the autosizing attributes right by selecting the Detail View Controller, and changing the orientation from Portrait to Landscape: Sorry can't load image for now...
You can Check or Change to "Landscape or Portrait" on the top right side "Simulated Metrics" select under "Size" the "Orientation".
If something isn’t right, don't worry: Just change it back to Portrait and double check the settings.

UIPopovercontroller detached from UIButton

I'm running into a problem with a detached UIPopovercontroller and am hoping someone has seen this behavior before.
My app runs in Landscape mode and offers a number of popover elements using the presentPopoverFromRect call. Some are launched from within the top view while others are presented from a view buried deep in the display. The popovers seem to work fine if the popover is presented from the upper 2/3rds of the iPad's display however when attempting to launch a popover from the bottom 1/3 of the display the popover is displayed detached from the UIButton. The x coordinate appears to be correct, however the y coordinate of the popover tends to be in the middle or top of the iPad screen.
I've played around with presenting the popover using a fixed position by creating a CGRect object in the lower 1/3 of the display but when the iPad renders the popover it either renders the popover in the upper 2/3rd of the view or the very bottom of the screen (if I force the CGRect value to a large y value).
At this point I'm out of ideas and hoping someone on the forum has seen this or can make suggestions as to what to try.
Thanks for any and all help,
Wes
I was able to fix my issue and thought that I'd share my solution incase someone else has the same problem.
The solution was to add a call to set the popover size BEFORE calling presentPopoverFromRect.
[mySettingsPopoverController setPopoverContentSize:CGSizeMake(320, 320) animated:YES];
[mySettingsPopoverController presentPopoverFromRect:sender.frame inView:self.navigationButtonsView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Before, I wasn't setting the popover content size prior to presenting the popover. In the viewDidAppear method of the viewcontroller of the popover I was resizing the popover to size to the tableview in the popover. Apparently by not setting the popovercontentsize before presenting the popover you get undefined behavior including the possibility of having the popover detach from the element that it is suppose to be attached to.
Wes

Resources