I have two view Controllers added as a sub-view in the UIWindow. Now the problem is one of the view gets view rotation calls but second is not getting calls for view changing orientation.
Now my problem is how we can get change orientation call for two different view controllers added in UIWindow.
UIWindow only sends rotation messages to its rootViewController. If you want the other view controller to receive them, you have two options:
Write code to make your rootViewController send the rotation messages to the other view controller.
Implement view controller containment. Watch the Implementing UIViewController Containment video from WWDC 2011 to learn how to do this.
Register for device orientation.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(detectOrientation) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
check in the method ,
if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) ||
([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) {
}
Related
So my iPhone application currently has a tabviewcontroller that populates the entire screen. The app only runs in portrait mode. My task has been to detect device orientation changes, and once it changes to landscape, have a new uiview populate the entire screen.
I already have the device orientation change detection working. I've used an NSNotificationCenter to successfully call a helper method, deviceOrientationChanged, once an orientation change is detected. IF the change was to landscape mode, I run a certain block of code.
In this block of code I have already tried various things, none of which are successful. Simply saying self.view = newViewThing; does not work because the statusbar is still present at the top and the tabs are still present at the bottom.
I have also tried adding this newViewThing as a subview to the UIWindow. This did not work because while the view was added, it was not oriented correctly.
THE QUESTION IS: is there a way to load an entirely new uiview once a device orientation change is detected? Thank you in advance.
Yes, there is a way to load a new view. I make it in my app that way:
- (void)orientationChanged:(NSNotification *)notification
{
// We must add a delay here, otherwise we'll swap in the new view
// too quickly and we'll get an animation glitch
[self performSelector:#selector(updateLandscapeView) withObject:nil afterDelay:0];
}
- (void)updateLandscapeView
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
{
[self presentModalViewController:self.landscapeView animated:YES];
isShowingLandscapeView = YES;
}
else if (deviceOrientation == UIDeviceOrientationPortrait && isShowingLandscapeView)
{
[self dismissModalViewControllerAnimated:YES];
isShowingLandscapeView = NO;
}
}
And also I have added this code to viewDidLoad:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification object:nil];
and this code to dealloc:
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
I am quite new to iOS and I am trying desperately to get orientation changes working in my app. After researching here's what I do:
In my app I have a NavigationController managing seven UIViewController subclasses.
In the projects summary tab I activated all 4 device orientations.
Each UIViewcontroller subclass has a xib file, all xib files have "autoresize subviews" activated.
The UIViewController subclasses all have:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight );
}
they also all have:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
and:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
implemented with an NSLog(...) statements (never printed, debugger also never entering these methods).
Also I was trying to use:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
BOOL getOrientationUpdates = [[UIDevice currentDevice] isGeneratingDeviceOrientationNotifications];
NSLog(#"will receive orientation notifications: %#", getOrientationUpdates?#"YES":#"NO");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
with
-(void)orientationChanged: (NSNotification*) notification
{
NSLog(#"orientationChanged");
}
and
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
respectively.
when I do beginGeneratingDeviceOrientationNotifications etc. in the AppDelegate's - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
method, orientationChanged: is called once on startup but never again however I rotate the device, when I do it in one of the UIViewController subclasses it is never called!
So far, all I want to achieve is getting orientation notifications to rotate an UIImageView and UIImage (without any layout changes in the different orientations).
UIDeviceOrientation o = [UIDevice currentDevice].orientation;
always returns UIDeviceOrientationPortrait
It might be that I missed something in the docs or on stackoverflow, but I obviously cannot figure out what I need to do/add to get it working in my setup. also I am quite new to stackoverflow, so I hope my post is not violating any platform conventions.
Any help/hints are greatly appreciated. Thank you so much!
EDIT:
getOrientationUpdates is always YES, which appears strange to me as the notification callback selector is never called when I rotate it!
EDIT: in my AppDelegate's didFinishLaunchingWithOptions I am doing:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.regScreenController = [[RegistrationScreenController alloc] initWithNibName:#"RegistrationScreenController" bundle:nil];
navCtrl = [[UINavigationController alloc]initWithRootViewController:self.regScreenController];
[navCtrl setNavigationBarHidden:YES];
self.window.rootViewController = self.regScreenController;
[self.window addSubview:navCtrl.view];
[self.window makeKeyAndVisible];
return YES;
See if you are setting the self.window.rootViewController in your AppDelegate's didFinishLaunchingWithOptions: method, because if you're adding only subviews to the window the orientation change notification does not fire.
What i would like to do is to rotate at landscape mode and leave the toolbar and navigation bar at ( vertical to the right for the toolbar and vertical to the left for the navigation bar), but only rotating the view and the icons on the toolbar and navigation bar..
What i have done so far is using the willAnimateSecondHalfofRotation.When going to landscapemode the position is what i wanted but i can see the transition from rotating and it looks bad.What i am trying to do is something like the camera of the iphone when only the icons of the toolbar are being rotating...
Could you help me?
Thanks in advanced.
Lor
Disable auto-rotation:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Register for UIDeviceOrientationDidChange notifications:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
Respond to device orientation changes:
- (void)orientationChanged:(NSNotification *)notification {
// Adjust views according to [[UIDevice currentDevice] orientation];
}
Don't forget to unregister
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
I have a navigation-based application in which I would like just one of the viewcontrollers to support landscape orientation. For that viewcontroller (vc1), in shouldAutorotate, I am returning YES for all orientations and in the other controllers I am returning YES only for portrait mode
But even then if the device is in landscape mode and I go to the next screen from vc1, the next screen also comes up rotated in landscape mode. I assumed that if I return a YES only for portrait mode, the screen should show up only in portrait.
Is this the expected behavior? How do I achieve what I am looking for?
Thanks.
You can't support the landscape orientation only for one of the viewcontrollers if you use shouldAutorotateToInterfaceOrientation method of UIViewController.
You have only two choice whether all viewcontrollers support the landscape or no viewcontrollers support it.
If you want to support the landscape only for one, You need to detect device rotation and manually rotate views in the viewcontroller.
You can detect the device rotation by using Notification.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
Then, you can rotate your views when you detect the device rotation.
- (void)didRotate:(NSNotification *)notification {
UIDeviceOrientation orientation = [[notification object] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft) {
[xxxView setTransform:CGAffineTransformMakeRotation(M_PI / 2.0)];
} else if (orientation == UIDeviceOrientationLandscapeRight) {
[xxxView setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)];
} else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
[xxxView setTransform:CGAffineTransformMakeRotation(M_PI)];
} else if (orientation == UIDeviceOrientationPortrait) {
[xxxView setTransform:CGAffineTransformMakeRotation(0.0)];
}
}
I have also situation when I need all view controllers in portait mode, but one of them also can rotate to landscape mode. And this view controller has navigation bar.
For this purpose I have created second window, in my case it was camera view controller. And when I need to show camera view controller, I show camera window and hide when I need to push another view controller.
And you also need to add this code to AppDelegate.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (window == self.cameraWindow)
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
return UIInterfaceOrientationMaskPortrait;
}
As i worked out for my App i advise you to use this solution.By using some conditions in the shouldAutorotateToInterfaceOrientation method orientation type we can solve this.Just try with this link will help you.
https://stackoverflow.com/questions/12021185/ios-rotate-view-only-one-view-controllers-view/15403129#154031
every UIViewController has a method called willRotateToInterface.
Is it possible to do this within a UIView too?
Does this match the idea of model view controller ?
The only way I can think of is to send the event from the UIViewController to the UIView.
Is there a global variable for the current orientation?
Observe UIDeviceOrientationDidChangeNotification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
...
- (void)orientationDidChange:(NSNotification *)note
{
NSLog(#"new orientation = %d", [[UIDevice currentDevice] orientation]);
}
UIDevice Class Reference
I should note that yo uneed to add -beginGeneratingDeviceOrientationNotifications when you want these notifications to be sent, and call -endGeneratingDeviceOrientationNotifications when you want them to stop. There is a battery impact of generating these, so you should only do so when your view is on screen. UIViewController does all this for you, so if you have a view controller, it is worth letting it do the work.
If you just want to adjust view to new size/layout when orientation changes, you should just override its layoutSubviews method.
It will be called whenever size of the view changes, which usually happens when view is rotated.
You can subscribe to a global notification and get a call when the device is rotated, it wont do anything for you though..
[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:#"UIDeviceOrientationDidChangeNotification" object:nil];