UIPopOverController issues while autorotation - uipopovercontroller

I am presenting a UIPopovercontroller using PresentPopOverFromRect: method. in Portrait Orientation. When i autorotate to Landscape UIPopoverController is not presenting at the proper position. How to position the UIPopoverController while autorotating the device.

You need to override this function:
- (void)willAnimateRotationToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
where you can change the dimension and position of the UIPopovercontroller depending of your current orientation. This function is convenient because it is called just before the screen is being redrawn and just before the user interface begins to rotate.
You should check this tutorial for an understanding of how you should handle the layout for different orientations of the IPad.

Yes, as tiguero says, in your custom UIViewController, you can override the method:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[self.popOverViewController dismissPopoverAnimated:NO];
CGRect yourNewRect = CGRectMake(0.0, 0.0, 20, 20);
[self.popOverViewController presentPopoverFromRect:yourNewRect inView:yourView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
You can have a try!

Related

How to resize an UITabBar selection indicator image in landscape

I'm customizing a UITabBar in a UITabBarController subclass ("CustomTabBarVC"). I wanted to use a custom selection indicator image, so I wrote this in the "CustomTabBarVC" implementation:
- (void)viewWillLayoutSubviews
{
CGFloat tabItemWidth;
UIView *tabItem = [[[self.tabBar items] lastObject] view];
tabItemWidth = tabItem.frame.size.width;
UIImage *selectionIndicator;
// Set here 'selectionIndicator' to an UIImage which fits 'tabItemWidth' and tab bar's height
[[UITabBar appearance] setSelectionIndicatorImage:selectionIndicator];
}
This works fine when the view is loaded in portrait, but when I change the orientation of the device to landscape, though the method is called again and selectionIndicator image seems to take the new width, it is no redrawn and the previous image keeps showing. How could I handle this?
Thanks
When your device orientation get changed, the default delegate will get called and you get your orientation in this method.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// do something before rotation
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// do something after rotation
}
Then implement viewWillAppear: and this method will get called after the orientation delegate. Now you can change your TabBar image in this method.

iOS set screen orientation programmatically, like method - setRequestedOrientation in Android

Background:
My app was configured in portrait view by default, but for one scene the screen should be in landscape view only.
Question:
How to set the orientation manually with codes, in other words, users need not to rotate the device to generate an event to make the screen rotated.
PS:
I need a method like "setRequestedOrientation" in Android or I need to know how to construct a screen rotation event to send to the system.
Have you on the desired view controller tried
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
Another thing you can do is to change the orientation on the desired view controller from "Inferred" to "Landscape" in the Attributes inspector in your storyboard.
UIViewController Class Reference
Key:
Use CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle) from CoreGraphics, which could make your view rotated
Sample Codes:
(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.view.transform = CGAffineTransformMakeRotation(M_PI/2);
self.view.frame = CGRectMake(0, 0, 480, 320);
}

IOS 6 view controller incorrect width / bounds - landscape mode

My app utilizes both landscape mode and portrait mode and the user can switch between the two at will.
When a view controller is presented by a parent view controller that is in portrait orientation, the opened view controller will have the correct width & frame.
However, if the parent view controller is in landscape mode, then on IOS6 (it works correctly on IOS7), the child view controller will be too large and actually a little too short also when it is presented.
Note this is not because the values are reported incorrectly since [[UIScreen mainScreen] bounds] reports the same values regardless of the orientation the child controller is loaded in.
Any ideas on how to fix this / why this is happening? Any idea on how to force the IOS6 versions to behave like IOS7 is now behaving natively? Many thanks!!!
Edit::
Here's how the vc's are presented:
AppDelegate
Launch1 *launch1 =[[Launch1 alloc] init];
self.window.rootViewController = launcher;
[self.window makeKeyAndVisible];
Launch1 class
Search *search = [[Search alloc] init];
[self presentViewController:search animated:YES completion:nil];
Search class
//load list_container
views = [[Search_custom_views alloc] initWithControllerContext:self];
[self.view addSubview:views];
Search_custom_views UIView extension:
- (id)initWithControllerContext:(UIViewController*)contextstart {
//set size of the screen
CGRect screenRect = [[UIScreen mainScreen] bounds];
self = [super initWithFrame:screenRect];
if (self) {
....
So this was a tough one. I load all my views programmatically. They basically are UIView subclasses that correspond to each view controller. For some reason, when an IOS6 view controller is opened from a parent view controller in landscape mode, the child view controller's bounds are not immediately passed on the child vc's UIView subclasses (if you just use addSubview in the viewDidLoad method of the controller--it is not enough). IOS7 does not have this problem.
The fix for IOS6 for me was doing the following in the viewDidLoad method of the child view controller:
//add view subclass to view controller
[self.view addSubview:views];
//reset bounds & refresh layout for IOS6
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7) {
views.frame = self.view.bounds;
[views layoutIfNeeded];
}
iOS 7 likes it when you call [[UIScreen mainScreen] bounds] instead of [[UIScreen mainScreen] applicationFrame] because the applicationFrame property is not consistently calculated between different versions of iOS, while bounds is.
It should be backwards compatible, so you should be able to do something like this:
- (CGRect)filterBankFrameForOrientation:(UIInterfaceOrientation)orientation {
CGRect appFrame = [[UIScreen mainScreen] bounds];
if (UIInterfaceOrientationIsLandscape(orientation)) {//using bounds here instead of applicationFrame for iOS7 compatibility
//Handle landscape orientation
filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.height, k_filterBankHeight);
}
else {
//Handle portrait orientation
filterBankFrame = CGRectMake(0.0, k_filterBankOffsetFromTop, appFrame.size.width, k_filterBankHeight);
}
return filterBankFrame;
}
and simply flip the height and width values as needed (since bounds will always be in "portrait" orientation)
Using bounds should give you the consistency you need for identical behavior across iOS versions and device sizes.
Updating in response to OP's updated code
One approach I'd recommend you at least consider is wiring up these views in InterfaceBuilder and using AutoLayout to worry about the rotations for you. It has the added benefit of gracefully handling ALL of the different screen sizes available too, so that can be nice too.
Still, creating and managing it all in code is perfectly acceptable too, and may be the right call for your situation. If so, you'll want to override a few of the rotation handling methods of UIViewController. Probably most or all of these:
– shouldAutorotate
– supportedInterfaceOrientations
– preferredInterfaceOrientationForPresentation
– willRotateToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation
at a minimum the first one and the last two.
To avoid being tied to one orientation only at launch, it is a common design pattern (citation needed) to write a method like the one I posted above, and then utilize it from both viewDidLoad as well as from the willRotate / didRotate class methods.
When calling during viewDidLoad, you do something like this:
_filterBank.collectionView.frame = [self filterBankFrameForOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
which uses the statusBarOrientation property to launch correctly in either landscape or portrait.
The willRotate / didRotate methods both give you a parameter you can pass to your frame generating method.
Your method gives you the right frame size, then it's all up to you to pass down this info and manipulate your view hierarchy accordingly. It's easier than it sounds...
(in your case, it looks like launcher would implement the methods, then coordinate the adjustments to launch1 and then down to search and finally to Search_custom_views)
(**last side note, you'll make more friends here by choosing SearchCustomViews instead of Search_custom_views)

Force parentView to refresh view after navigation controller pops out a child view

I have secondViewController that can display content in both landscape and portrait view. The MainViewController (parent of secondViewController) can only display content in landscape mode.
When SecondView is in portrait mode and is pop out, the view the MainViewController (which is supposed to display content in landscape mode only) displays content in portrait. It does not refresh to landscape mode.
Is there a way to force MainViewController to refresh the content?
On the MainViewController's viewWillAppear method, I have added setNeedsDisplay and layoutSubviews, etc.
-(void) viewWillAppear:(BOOL)animated {
[self.view setNeedsDisplay];
[self.view layoutIfNeeded];
[self.view layoutSubviews];
}
but it is not reloading the view. I also tried the navigation controller's delegate method - willShowViewController but its not working.
I solved a similar problem by not letting he user "go back" to the other view unless the app was in the proper orientation (in this case Landscape). What you can do is provide your own "Back" button, and if the view is in Portrait, pop an alert that says please rotate to Landscape first (or better yet animate a small view in from the bottom or top of the screen). Or just hide or disable the back button in portrait (I hid the button).
Its a terrible UI choice to let the user go back, and see the view in landscape while the phone is in portrait mode in any case.
Looks like if you remove the view and add it back it works
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (UIDeviceOrientationIsPortrait(orientation)){
NSLog(#"force to landscape mode ");
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
}
You can also use CGAffineTransformMakeRotation but it the rotation does not work on the navigation controller
if (orientation == UIDeviceOrientationPortraitUpsideDown) {
[self.view setTransform:CGAffineTransformMakeRotation(M_PI/-2.0)];
//[self.navigationController.view setTransform:CGAffineTransformMakeRotation(M_PI/-2.0)];
} else if (orientation == UIDeviceOrientationPortrait) {
[self.view setTransform:CGAffineTransformMakeRotation(M_PI/2.0)];
//[self.navigationController.view setTransform:CGAffineTransformMakeRotation(M_PI/-2.0)];
}

UITabBar autorotate issue

I'm wondering why iPad project based on UITabBarController won't autorotate when i specify some of the tab should autorotate in landscape mode and the other will autorotate in landscape and portrait mode.
i've used the
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
for all the UIViewController and specify if landscape return YES; other wise return NO;
In the other hand, if the UIViewController should rotate in landscape and portrait i've justreturn YES;` always.
Thx in advance.
for all the UIViewController you are loading in tabbarcontroller you must return True in
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
Note:
A tab bar controller will not auto rotate unless ALL the controllers it contains also auto rotate.
from Rotate one UIViewController in UITabBar application -->>
There is no easy way to have only one view in landscape mode, while the others are in landscape, nor an easy way to programmatically switch to landscape mode.
One possible approach would be using a CGAffineTransform to transform your view in your viewWillAppear (i.e., right before the view is shown):
- (void)viewWillAppear:(BOOL)animated; {
//-- Adjust the status bar
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
//-- Rotate the view
CGAffineTransform toLandscape = CGAffineTransformMakeRotation(degreesToRadian(90));
toLandscape = CGAffineTransformTranslate(toLandscape, +90.0, +90.0 );
[self.view setTransform:toLandscape];
}

Resources