I am trying to change the orientation of a single UIViewController programmatically. The user should choose in the settings if the view will be portrait or not. The value will be saved in NSUserDefaults and in the specific ViewController the orientation should be changed. So if Portrait is on the interfaceOrientation should be on UIInterfaceorientationUpsideDown......
I used following method but it will only change the orientation when the user will turn the device to landscape/portrait... otherwise nothing will be triggered.
- (BOOL)shouldAutoRotateToInterfactOrientation:(UIInterfaceOrientation)interfaceOrientation
Furthermore i tryied the next one (also with method name "setOrientation"):
[[UIDevice currentDevice] orientation: UIDeviceOrientationPortraitUpsideDown];
But again, nothing happens, there just appear errors because xcode sayes there are no methods with this name.
But ther should be another way to change it programatically...
the first method is also just a method that handles the actionListener after device position but there should be a way to call this actionListener in a direct way....
I just looked inside the UIApplication File but there is no usefull method....
You should use something like this code:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(rotationChanged:)
name:#"UIDeviceOrientationDidChangeNotification"
object:nil];
And then, change your view according to the orientation:
-(void)rotationChanged:(NSNotification *)notification{
NSInteger orientation = [[UIDevice currentDevice] orientation];
UIWindow *_window = [[[UIApplication sharedApplication] delegate] window];
switch (orientation) {
case 1:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
[_window setTransform:CGAffineTransformMakeRotation (0)];
[_window setFrame:CGRectMake(0, 0, 320, 480)];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
[UIView commitAnimations];
break;
case 2:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
[_window setTransform:CGAffineTransformMakeRotation (M_PI)];
[_window setFrame:CGRectMake(0, 0, 320, 480)];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
[UIView commitAnimations];
break;
case 3:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
[_window setTransform:CGAffineTransformMakeRotation (M_PI / 2)];
[_window setFrame:CGRectMake(0, 0, 320, 480)];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
[UIView commitAnimations];
break;
case 4:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
[_window setTransform:CGAffineTransformMakeRotation (- M_PI / 2)];
[_window setFrame:CGRectMake(0, 0, 320, 480)];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:YES];
[UIView commitAnimations];
break;
default:
break;
}
}
Hope it helps :P
Use this works perfectly on iOS7 and earlier.
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
forKey:#"orientation"];
[[UIApplication sharedApplication] setStatusBarOrientation:yourDesiredOrientation];
You will then need to edit the shouldAutoRotate method (following example is for portrait:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
From previous answer:
[[UIDevice currentDevice] setValue:
[NSNumber numberWithInteger: UIInterfaceOrientationPortrait]
forKey:#"orientation"];
WARNING
I haven't a possibility to comment this answer so I'll edit it.
The author of this answer tries to set a value of UIInterfaceOrientation type to a variable of UIDeviceOrientation. They are both NSInteger enums, so compiler will not show a warning/error. But they have different meanings and "device" additionally has "face up" and "face down" orientations.
Related
I have added a viewcontroller in the window of appdelegate class like this:
-(void)showSearchView:(BOOL)view
{
if(view)
{
searchViewController = [[SearchView alloc] initWithNibName:#"SearchView" bundle:nil];
CGRect viewFrame=searchViewController.view.frame;
viewFrame.origin.y=-1024;
viewFrame.origin.x=248;
[window addSubview:searchViewController.view];
searchViewController.view.frame = viewFrame;
[UIView beginAnimations:#"UIBase Hidden" context:nil];
[UIView setAnimationDuration:0.5];
searchViewController.view.transform = CGAffineTransformMakeTranslation(0,1024);
[UIView commitAnimations];
}
else
{
[UIView beginAnimations:#"UIBase Shown" context:nil];
[UIView setAnimationDuration:0.5];
searchViewController.view.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
[self performSelector:#selector(doTHis) withObject:nil afterDelay:1];
}
}
This gets called from other classes through this command
[apd showSearchView:YES];
where apd is object of appdelegate class
Everything is working fine till here but when i try to rotate it does not rotate. I have even returnd YES in the following method and still it does not rotate:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
What should be done?
Please remember that UIWindow does not rotate. Perhaps You should add a base view controller and do your rotation.
in my app I got a Home with several buttons. Each button opens a separate view. In each view, if I put the device in landscape a help view is shown. Everything works fine except that in whatever view I am, if I put the iPhone like to lay on a table (I don't know how to eplain better...) the app exites from that view and comes back to the first view, the Home.
Here's my code:
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)name:#"UIDeviceOrientationDidChangeNotification"
object:nil];
[self performSelector:#selector (ritardo) withObject:nil afterDelay:5.0f];
}
-(void)orientationChanged:(NSNotification *)object{
UIDeviceOrientation deviceOrientation = [[object object] orientation];
if (deviceOrientation == UIInterfaceOrientationPortrait)
{
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
self.view = self.portraitView;
}
else if (deviceOrientation == UIInterfaceOrientationLandscapeLeft || deviceOrientation
== UIInterfaceOrientationLandscapeRight)
{
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
self.view = self.landscapeView;
}
[UIView commitAnimations];
[self dismissModalViewControllerAnimated:NO];
}
-(void) ritardo {
ruota.image = [UIImage imageNamed:#"RuotaPerAiuto.png"];
}
- (void)viewDidUnload
{
[self setPortraitView:nil];
[self setLandscapeView:nil];
[self setRuota:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
Hi hope you can help me
EDIT:
I modified the -(void)orientationChanged:(NSNotification *)object{ in this way:
-(void)orientationChanged:(NSNotification *)object{
UIDeviceOrientation deviceOrientation = [[object object] orientation];
if (deviceOrientation == UIDeviceOrientationFaceUp)// || deviceOrientation ==
UIDeviceOrientationFaceDown)
{
return;
}
if (deviceOrientation == UIInterfaceOrientationPortrait || deviceOrientation ==
UIInterfaceOrientationPortraitUpsideDown)
{
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
self.view = self.portraitView;
}
else
if (deviceOrientation == UIInterfaceOrientationLandscapeLeft || deviceOrientation ==
UIInterfaceOrientationLandscapeRight)
{
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
self.view = self.landscapeView;
}
[UIView commitAnimations];
[self dismissModalViewControllerAnimated:NO];
}
Now, if I'm in portrait and get the iPhone to faceUp position works good. But when I change position from faceUp to portrait it goes back to the home...
The problem is that UIDeviceOrientationDidChangeNotification will be fired independently from shouldAutorotateToInterfaceOrientation. And you don't handle the cases UIInterfaceOrientationPortraitUpsideDown, UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown in the method orientationChanged:. So when the device is rotated to one of these orientations, your code is equivalent to:
-(void)orientationChanged:(NSNotification *)object
{
[UIView commitAnimations];
[self dismissModalViewControllerAnimated:NO];
}
So you should remove the lines:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:)name:#"UIDeviceOrientationDidChangeNotification" object:nil];
and put you code in the method willRotateToInterfaceOrientation:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
if (UIInterfaceOrientationIsPortrait(interfaceOrientation)) {
self.view = self.portraitView;
} else {
self.view = self.landscapeView;
}
[UIView commitAnimations];
[self dismissModalViewControllerAnimated:NO];
}
Edit
If you want to keep orientationChanged, then modify it as follows:
-(void)orientationChanged:(NSNotification *)object{
UIDeviceOrientation deviceOrientation = [[object object] orientation];
if (deviceOrientation == UIInterfaceOrientationPortrait) {
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
self.view = self.portraitView;
[UIView commitAnimations];
[self dismissModalViewControllerAnimated:NO];
} else if (deviceOrientation == UIInterfaceOrientationLandscapeLeft || deviceOrientation == UIInterfaceOrientationLandscapeRight) {
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
self.view = self.landscapeView;
[UIView commitAnimations];
[self dismissModalViewControllerAnimated:NO];
}
}
Is there an alternative for [[UIApplication sharedApplication] setStatusBarOrientation:animated:]? setStatusBarOrientation, as you can see in it's name, only rotates the status bar. Is there anything that will rotate the whole app like it does when physically rotating the device?
If you want to change the orientation manually (not using autorotation), you will have to rotate and position views yourself, as described in answers to this question. Supporting autorotation is described in the documentation.
if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
if (!window) {
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
}
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
window.transform = CGAffineTransformMakeRotation(-M_PI);
[UIView commitAnimations];
}
Note: you need the coregraphics framework, I guess.
You can indeed force a rotation this way:
if ([[UIDevice currentDevice] respondsToSelector: #selector(setOrientation:)]) {
[[UIDevice currentDevice] setOrientation: UIInterfaceOrientationPortrait];
}
Change UIInterfaceOrientationPortrait to UIInterfaceOrientationLandscape if you wish to rotate to landscape
I have a UIToolbar at bottom of my view, and I have a UITextField in this toolbar. When I begin editing this field, it is hidden behind the keyboard. To see what I've typed, I want to move the toolbar up at the moment the keyboard is presented (and then move it back down when I've finished editing).
How do I move this UIToolbar up/down?
add your viewController class to the list of observers of UIKeyboardWillShowNotification/UIKeyboardWillHideNotification. then you can move your view to make your textView visible. You can also get animation parameters from this notifications to synchronize your animation with keyboard animation parameters of the current OS version. this code I've used for paging
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(liftMainViewWhenKeybordAppears:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(returnMainViewToInitialposition:) name:UIKeyboardWillHideNotification object:nil];
}
- (void) viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
in the methods below I set two methods to handle keyboard notifications. and here are this methods:
- (void) liftMainViewWhenKeybordAppears:(NSNotification*)aNotification{
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - keyboardFrame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
- (void) returnMainViewToInitialposition:(NSNotification*)aNotification{
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + keyboardFrame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
Thanks that worked!
Here is a slight improvement:
- (void) liftMainViewWhenKeybordAppears:(NSNotification*)aNotification{
[self scrollViewForKeyboard:aNotification up:YES];
}
- (void) returnMainViewToInitialposition:(NSNotification*)aNotification{
[self scrollViewForKeyboard:aNotification up:NO];
}
- (void) scrollViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];
// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame];
// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + (keyboardFrame.size.height * (up?-1:1)), self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
Building on the answers above and using the convenience method [UIView animateWithDuration...]. Observe the will show/hide keyboard notifications and use these handlers.
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
NSNumber *durationValue = info[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curveValue = info[UIKeyboardAnimationCurveUserInfoKey];
NSValue *endFrame = info[UIKeyboardFrameEndUserInfoKey];
[UIView animateWithDuration:durationValue.doubleValue
delay:0
options:(curveValue.intValue << 16)
animations:^{
self.navigationController.toolbar.frame = CGRectMake(0,
[endFrame CGRectValue].origin.y - self.navigationController.toolbar.bounds.size.height,
self.navigationController.toolbar.bounds.size.width,
self.navigationController.toolbar.bounds.size.height);
}
completion:nil];
}
- (void)keyboardWillHide:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
NSNumber *durationValue = info[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curveValue = info[UIKeyboardAnimationCurveUserInfoKey];
[UIView animateWithDuration:durationValue.doubleValue
delay:0
options:(curveValue.intValue << 16)
animations:^{
self.navigationController.toolbar.frame = CGRectMake(0,
self.view.bounds.size.height - self.navigationController.toolbar.bounds.size.height,
self.navigationController.toolbar.bounds.size.width,
self.navigationController.toolbar.bounds.size.height);
}
completion:nil];
}
Thank you so much for this; it works great. However, the code as presented has 2 limitations as I experienced them:
1) The view being repositioned simply slides up out of the screen rather than resizing to fit the space available after the keyboard appears
2) Repeat notifications due to switching text fields continue to apply the frame change, causing the view to incrementally fly off the screen.
The cause is that the above is a reposition relative to the view's current frame rather than a resize relative to the keyboard. Here are two amended lines of code which fix this:
In liftMainViewWhenKeybordAppears:, resize rather than reposition, relative to the keyboard:
keyboardFrame = [self.view.window convertRect:keyboardFrame toView:self.view.superview];
CGRect superviewFrame = [self.view.window convertRect:self.view.superview.frame toView:self.view];
[self.view setFrame:CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
superviewFrame.size.height - keyboardFrame.size.height)];
In returnMainViewToInitialposition:, change the animation to this setFrame: (essentially akin to the identity transform).
[self.view setFrame:CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
keyboardFrame.origin.y + keyboardFrame.size.height)];
Here is a more elegant solution using uiview category
#import <Foundation/Foundation.h>
#interface UIView(AnimationUtils)
-(void)scrollControlToCenter:(UIView *)view;
-(void)scrollViewToOriginalPosition;
#end
#import "UIView+AnimationUtils.h"
#implementation UIView(AnimationUtils)
#pragma mark ScrollView Methods
//Method Called whenever keyboard appears
- (void)scrollControlToCenter:(UIView *)view {
if([view isKindOfClass:[UITextField class]]){
CGRect viewFrame = [view frame];
float verticalDistance = 216.0f - viewFrame.origin.y - (2*viewFrame.size.height);
if(viewFrame.size.height >= (460 - 216)/2){
verticalDistance = 0;
}
[UIView beginAnimations:#"ScrollToCenter" context:nil];
[UIView setAnimationDuration:0.5];
[self setFrame:CGRectMake(0, verticalDistance, self.frame.size.width, self.frame.size.height)];
[UIView commitAnimations];
}else if([view isKindOfClass:[UITextView class]]){
[UIView beginAnimations:#"ScrollToTop" context:nil];
[UIView setAnimationDuration:0.5];
UIView *viewBG = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[viewBG setTag:5];
[viewBG setBackgroundColor:[UIColor blackColor]];
[viewBG setAlpha:0.75];
[self addSubview:viewBG];
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height)];
[self setFrame:CGRectMake(0, -view.frame.origin.y , self.frame.size.width, self.frame.size.height)];
[self insertSubview:view atIndex:[self.subviews count] + 1];
[UIView commitAnimations];
}
}
-(void)scrollViewToOriginalPosition{
[UIView beginAnimations:#"ScrollToOriginal" context:nil];
[UIView setAnimationDuration:0.5];
for(UIView *view in self.subviews){
if(view.tag == 5){
[view removeFromSuperview];
}
}
[self setFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[UIView commitAnimations];
}
#pragma mark -
#end
In my app I try to use the TTphotoView, so in a ViewController I push the TTphotoView with my navigationController like this:
if(self.photoViewController == nil {
PhotoViewController *viewController = [[PhotoViewController alloc] init];
self.photoViewController = viewController;
viewController.hidesBottomBarWhenPushed = YES;
[viewController release];
}
[self.navigationController pushViewController:self.photoViewController animated:YES];
[self.navigationController dismissModalViewControllerAnimated:YES]
the problem is when the user rotate the device on the PhotoViewController nothing happen.
EDIT : I can't believe people didn't have the same problem. If someone use the photoView in his application with his own navigation and not the TTNavigation can he tell me how did he push the ViewController?
I had the same problem.
I don't know why but TTScrollView deviceOrientationDidChange method in three20 code is commented out! If you uncomment it, it will work.
See the code here: http://github.com/facebook/three20/blob/master/src/TTScrollView.m
Have you overridden your application's:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
and returned YES for the landscape orientations?
My comment for willcodejavaforfood, as I told you I can force by doing something like for example that but too many problem inside, and the PhotoViewController of three20 must do it by himself so I don't want that:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
-(void) receivedRotate: (NSNotification *) notification {
NSLog(#"ORIENTATION CHANGE");
UIDeviceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];
if(interfaceOrientation == UIDeviceOrientationLandscapeRight) {
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration: 0.5f];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(-M_PI/2);
self.view.bounds = CGRectMake(0.0, 0.0, 480.0, 320.0);
self.view.center = CGPointMake(240.0f, 160.0f);
[UIView commitAnimations];
}
}