How can I write my code which supports both landscape and portrait? I tried this one -
(void)setupForOrientation:(UIInterfaceOrientation)orientation {
if (UIInterfaceOrientationIsPortrait(orientation)) {
CGRect bounds = CGRectMake(0, 0, 768, 1004);
scrollView.frame = bounds;
// Other view positioning for portrait.
} else {
CGRect bounds = CGRectMake(0, 0, 1024, 748);
scrollView.frame = bounds;
// Other view positioning for landscape.
}
[self drawBackgroundForOrientation:orientation];
}
But its not working. Please help me.
Use this code:
- (void)viewDidLoad
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
}
- (void) orientationChanged:(id)object
{
if( [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft || [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight )
{
self.view=self.landscapeView;
NSLog(#"ViewwillAppear= Land");
}
else
{
self.view = self.portraitView;
NSLog(#"ViewwillAppear= Port");
}
You'll always have to return yes for this function whenever you require orientation support.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
Edit 1: P.S. I've taken portraitView & landscapeView as two separate UIViews.
I think you want to override the shouldAutorotateToInterfaceOrientation: method of your main view controller to always return YES. That or you can specify the supported orientations for your app in the app properties.
You have to use following method to support both orientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
//this method will call just before changing Orientation of device you can set frames in this method
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
}
If you have used viewcontrollers then there are a few methods that you can override. The first being
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation; // Override to allow rotation. Default returns YES only for UIInterfaceOrientationPortrait
Where you can specify whether a particular view will support rotation or not.
If you need to configure your views manually according to the orientation you can override the following methods
As per the documentation
Your implementation of this method should simply return YES or NO based on the value in the interfaceOrientation parameter. Do not attempt to get the value of the interfaceOrientation property or check the orientation value reported by the UIDevice class. Your view controller is either capable of supporting a given orientation or it is not.
// Notifies when rotation begins, reaches halfway point and ends.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
AND
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
To achieve what you wish to implement you can return YES for supported orientation and then use the second method to configure your view accordingly by calling [self setupForOrientation:orientation];
Hope it helps!!!
Related
I know similar questions have been asked before, but this is a more specific use case (controlling orientation from a static library, cannot write in root view controller).
I have a static library which adds UI elements as overlays to a passed view controller (the client's root view controller) as subviews. Problem is our UI elements support portrait orientation only, while our client's application may support both portrait and landscape. This is fine, as long as our UI elements don't autorotate when our client's views do.
I'd like to lock the orientation to portrait only for our view controller only. In iOS 6, when I use the following code in my library's view controller, it doesn't affect the behaviour of autorotate at all:
-(BOOL)shouldAutorotate{
return NO;
}
-(NSInteger)supportedInterfaceOrientations{
NSInteger orientationMask = 0;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortrait])
orientationMask |= UIInterfaceOrientationMaskPortrait;
return orientationMask;
}
When I put the same code in the root view controller, it works perfectly, with the app no longer auto-rotating. However, this is not an option for us since in production we will not have access to our client's root view controller. Is there a way to either lock view orientation from NOT a root view controller, or lock orientation for a single view controller only? Any other way of achieving what we need that I'm not thinking of? Hoping for solutions that work in iOS <= 6 if at all possible
You can't lock orientation only for one view controller in whole application . So you have to set transform angle with parent view frame on view launch and on change of orientation.
You add code for those view controller class
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
[[self view] setBounds:CGRectMake(0, 0, self.view.frame.size.height, self.view.frame.size.width)];
CGFloat radians = atan2f(self.view.transform.b, self.view.transform.a);
if (radians!=M_PI_2) {
[[self view] setTransform:CGAffineTransformMakeRotation(M_PI_2)];
}
}
}
(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
[[self view] setBounds:CGRectMake(0, 0, self.view.frame.size.height, self.view.frame.size.width)];
CGFloat radians = atan2f(self.view.transform.b, self.view.transform.a);
if (radians!=M_PI_2) {
[[self view] setTransform:CGAffineTransformMakeRotation(M_PI_2)];
}
}else{
[[self view] setBounds:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGFloat radians = atan2f(self.view.transform.b, self.view.transform.a);
if (radians!=0) {
[[self view] setTransform:CGAffineTransformMakeRotation(0)];
}
}
}
enter image description herehai, i have a list of buttons in a view which is a sub view of another UIView. i need to rearrange these buttons in order while the device orientation changes to landscape mode.
is their any way to do this? or else i need to do all these things manually by repositioning all buttons?
shouldAutorotateToInterfaceOrientation:, mentioned in the other answers, is for letting your view controller decide whether or not to allow autorotation to a given orientation. (you're supposed to return YES or NO).
If you really want to programmatically adjust layout of your subviews, you would do it in either
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[UIView animateWithDuration: duration
delay: 0.0f
options: UIViewAnimationOptionCurveLinear
animations: ^(void) {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
self.button.frame = CGRectMake(x1, y1, self.button.frame.size.width, self.button.frame.size.height);
} else {
self.button.frame = CGRectMake(x2, y2, self.button.frame.size.width, self.button.frame.size.height);
}
}
completion: ^(BOOL finished) {
// code to run after animation completes can go here
}];
}
or, you can use willAnimateRotationToInterfaceOrientation:duration: for one-step rotations.
Not only is it only called when the autorotation actually happens, but it gives you the duration of the animation. This allows you to wrap any animatable view property changes inside your own animation, so that they smoothly animate during the rotation, instead of just snapping to their new values.
But, really, this is usually not the best way to solve the problem. See this link for a more general discussion of the issue
Change the CGFrame of you buttons in the
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation==UIInterFaceOrientationPortrait)
{
Button1.frame=...;
Button2.frame=....;
}
else if(interfaceOrientation==UIInterFaceOrientationLandscapeLeft)
{
Button1.frame=...;
Button2.frame=....;
}
return YES;
}
1-you can use this
YOUR_OBJECT.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin;
OR
2- use frame property with CGRectMake for your object in
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
if(interfaceOrientation==UIInterFaceOrientationPortrait)
else if(interfaceOrientation==UIInterFaceOrientationLandscapeLeft)
You can handle it via
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
method.
Make two methods in your viewController.h class assume they are -
-(void)viewForPortraitMode;
-(void)viewForLandscapeMode;
And this is the body part of both in your viewcontroller.m file.
//Set frame according to you
-(void)viewForPortraitMode
{
[btn1 setFrame:CGRectMake(117.0, 383.0, 87.0, 37.0)];
[btn2 setFrame:CGRectMake(40.0, 20.0, 240.0, 324.0)];
}
-(void)viewForLandscapeMode
{
[btn1 setFrame:CGRectMake(200.0, 252, 87.0, 37.0)];
[btn2 setFrame:CGRectMake(20.0, 7.0, 446.0, 228.0)];
}
And call these two methods in this
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
[self viewForPortraitMode];
}
else
{
[self viewForLandscapeMode];
}
return YES;
}
I searched every where but not find the solution of this I am New in iphone.In every where I got the set the height of navigation or my view is not rotating in orientation like issue.my view is rotating but my navigation bar is on same position please some one help me if You have solution.Thanks I have show my some code in down which I used for Orientation.when I tap on my tab bar my simulator is automatic rotate and I want tab bar also rotate but using this code only simulator is rotate not tab bar and navigation bar and sorry for my bad english.
CGAffineTransform transform = CGAffineTransformIdentity;
switch ([[UIApplication sharedApplication] statusBarOrientation])
{
case UIInterfaceOrientationPortrait:
transform = CGAffineTransformMakeRotation(M_PI_2);
break;
default:
break;
}
[[UIApplication sharedApplication]setStatusBarOrientation:UIInterfaceOrientationPortrait];
[UIView animateWithDuration:0.2f animations:^ {
[self.navigationController.view setTransform:transform];
}];
[self.view setFrame:CGRectMake(0, 0, 320, 480)];
[self.view setNeedsLayout];
This code is, no offense intended, very curious. I'm not sure what you are trying to do. What problem are you trying to solve? Playing around with CGAffineTransform's can definitely generate strange results like what you describe if you're not very careful.
If you just want to make sure that your app successfully supports landscape and portrait orientations, you can implement shouldAutorotateToInterfaceOrientation in your view controller. When you do this, all of the various controls will reorient themselves accordingly.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Support all orientations on iPad
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
return YES;
// otherwise, for iPhone, support portrait and landscape left and right
return ((interfaceOrientation == UIInterfaceOrientationPortrait) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
But if I have misunderstood what you're trying to do, i.e., you're trying to do something more sophisticated than just supporting both landscape and portrait orientation, let me know.
I apologize because I don't remember where I originally got this code (but it's referenced in SO here), but the following can be used to force landscape orientation:
First, make sure that your shouldAutoRotateToInterfaceOrientation should read as follows:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeRight))
return YES;
else
return NO;
}
Second, in viewDidLoad, add the following code:
if (UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))
{
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
}
For some reason, removing the view from the main window and then re-adding it forces it to query shouldAutorotateToInterfaceOrientation and set the orientation correctly. Given that this isn't an Apple approved approach, maybe one should refrain from using it, but it works for me. Your mileage may vary. But that SO discussion also refers to other techniques, too.
I have created an application to support all orientations.
Also I have created a table and search bar in viewDidLoad method (without using xib). I have also written following code to adjust the positioning of table view and search bar.
It works properly when I launch my application in portrait view and when I rotate to landscape view, it adjust the views perfectly.
But when I launch my application in landscape mode, views are not adjusted, instead they take positioning of portrait view. But again when I rotate in portrait and then landscape it works all right.
Also to ensure that correct orientation is captured, I have written NSLog inside this method, and it shows me the correct value.
Also to ensure that this method (adjustViewsForOrientation) is called explicitly, I have called the method in viewDidLoad as well.
[self adjustViewsForOrientation:self.interfaceOrientation];
Here is a rest of code snippet:
- (void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation {
if (orientation == UIInterfaceOrientationLandscapeLeft ||
orientation == UIInterfaceOrientationLandscapeRight) {
aTableView.frame = CGRectMake(705, 220, 320, 280);
sBar.frame=CGRectMake(805, 0, 220, 40);
NSLog(#"inside landscape");
}
else if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown) {
aTableView.frame = CGRectMake(450, 220, 320, 280);
sBar.frame=CGRectMake(550,3,220,40);
}
}
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
// [self adjustViewsForOrientation]
[self adjustViewsForOrientation:toInterfaceOrientation];
NSLog(#"landscap");
}
Try this approach, it may help. Register for UIDeviceOrientationDidChange in viewDidLoad method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(adjustViewsForOrientation:) name:UIDeviceOrientationDidChangeNotification object:nil];
and also change -(void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation
to -(void) adjustViewsForOrientation:(NSNotification *)notification
and obtain the new orientation by getting the orientation value
e.g. UIDeviceOrientation newDeviceOrientation = [notification orientation];
I would like to implement the following. When the user rotates the iPhone, I want to instantiate a new UIViewController (automatically upon rotation, not clicking a button or performing a similar action) and show to the user a view handled by this new UIViewController in landscape orientation. How to do this properly ?
I tried to instantiate the new controller in the methods willRotateToInterfaceOrientation and didRotateFromInterfaceOrientation, but none of this methods gets called!. I suspect this is because the current controller is pushed in by a navigation controller which is itself handled by a tabBarController. Any clue? A simple code snippet would be greatly appreciated.
Thank you in advance.
A cleaner way is NOT to use UIInterfaceOrientation for the rotation.
Why, because then your interface or view 1 actually rotates. This means you have to rotate it back to redisplay it after view 2 is removed.
To compensate for this, I simple subscribe to UIDeviceOrientation notifications. Subtly different. View 1 does NOT have to support autorotation to make this method work. In viewDidLoad enter the following code:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(detectOrientation) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
Then just define the method detectOrientation:
-(void) detectOrientation {
if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) ||
([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) {
//load view 2
} else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait) {
// load view 1
}
}
Now neither of your views need support autoratation! You will however need to perform a transform on view 2 before loading:
-(void) transformView2ToLandscape {
NSInteger rotationDirection;
UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
if(currentOrientation == UIDeviceOrientationLandscapeLeft){
rotationDirection = 1;
}else {
rotationDirection = -1;
}
CGRect myFrame = CGRectMake(0, 0, 480, 300);
CGAffineTransform transform = [[self view2] transform];
transform = CGAffineTransformRotate(transform, degreesToRadians(rotationDirection * 90));
[[self view2] setFrame: myFrame];
CGPoint center = CGPointMake(myFrame.size.height/2.0, myFrame.size.width/2.0);
[[self view2] setTransform: transform];
[[self view2] setCenter: center];
}
Thats how I swap views o rotation without supporting autorotation in my views.
I've implemented this exact type of behavior on an app and the key is to make sure that any parent controllers implement shouldAutorotateToInterfaceOrientation and that your current view controller also implements it. In my case I am using a tab controller which intercepts the call to shouldAutorotateToInterfaceOrientation and I had to override the tab controller to get the call to fall through. The default behavior of view controllers is to display in portrait mode only.
So you need to force them to allow all orientation changes through:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Then in order to load a new view controller you should respond to:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if((fromInterfaceOrientation == UIInterfaceOrientationPortrait) ||
(fromInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown))
{
// Load the view controller you want to display in landscape mode...
}
}
and can also use:
-(void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
To detect that the orientation change is coming.
In my case I am using didRotateFromInterfaceOrientation to check if the last orientation was portrait and if so load the view I want displayed in landscape mode.
I then implemented the same methods in the viewcontroller I am loading and it is responsible for detecting when the orientation changes back to portrait and dismissing itself from the view stack.
Hope that helps a little.
Paul
Indeed only top-level controller is notified. You're responsible for notifying nested controllers.
Add this to your tab bar controller:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[self.selectedViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
Do you implement shouldAutorotateToInterfaceOrientation? If not, then that might be why you aren't getting the messages.