How would I do this, all I want to do is rotate a UIImageView depending on the orientation of the iPhone.
You can do this through IB, to get an app with a portrait and a landscape layout, or you can do it programmatically. This is about the programmatic way.
To get notifications on the change of orientation, use
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged)
name:UIDeviceOrientationDidChangeNotification
object:nil];
and add a function like this (note this is copypasted from a project and a lot of lines are left out, you will need to tune the transformation to your specific situation)
-(void)orientationChanged
{
UIDeviceOrientation o = [UIDevice currentDevice].orientation;
CGFloat angle = 0;
if ( o == UIDeviceOrientationLandscapeLeft ) angle = M_PI_2;
else if ( o == UIDeviceOrientationLandscapeRight ) angle = -M_PI_2;
else if ( o == UIDeviceOrientationPortraitUpsideDown ) angle = M_PI;
[UIView beginAnimations:#"rotate" context:nil];
[UIView setAnimationDuration:0.7];
self.rotateView.transform = CGAffineTransformRotate(
CGAffineTransformMakeTranslation(
160.0f-self.rotateView.center.x,
240.0f-self.rotateView.center.y
),angle);
[UIView commitAnimations];
}
When you're done, stop the notifications like so:
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
Related
I want to support all orientations but portrait. I wanted to do some simple but I never was not able to find a solution.
I have 6 big buttons in my interface. Plus 2 extra small buttons.
When the orientation changes, I want to keep ALL 8 buttons in the same center/place, I just wanted to rotate the 6 big buttons, so they will be facing the right way.
I tried setting
- (BOOL)shouldAutorotate
{
return NO;
}
and sending myself a notification but I would have to deal with the old orientation vs the new orientation in order to rotate to the right position. Is there any other possibility? Plus I was never able to get the previous orientation as the notification was sent after the orientation changed (UIDeviceOrientationDidChangeNotification)
This is what I use to rotate a button's image when the view rotate:
- (BOOL)shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleDeviceOrientationDidChangeNot:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)handleDeviceOrientationDidChangeNot:(NSNotification *)not {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
CGFloat angle = 0.0;
switch (orientation) {
case UIDeviceOrientationPortrait:
angle = 0.0;
break;
case UIDeviceOrientationLandscapeLeft:
angle = M_PI/2;
break;
case UIDeviceOrientationPortraitUpsideDown:
angle = M_PI;
break;
case UIDeviceOrientationLandscapeRight:
angle = -M_PI/2;
break;
default:
return;
break;
}
[UIView animateWithDuration:0.35 animations:^{
self.someButton.imageView.transform = CGAffineTransformMakeRotation(angle);
} completion:^(BOOL finished) {
//
}];
}
I want to create a view, like the Facebook or Twitter app's share dialog, for example, where there is just a UITextView and a permanent keyboard. I can see how to start with the keyboard visible from this answer, but I'm not sure how to size the UITextView to fit exactly above the keyboard. If I don't, text can get hidden under the keyboard which is awkward.
You can subscribe to UIKeyboardWillShowNotification. The notification includes the frame of the keyboard, so you can size your view to fit the remaining space.
I found a helpful code sample in the Apple documentation for this: https://developer.apple.com/library/ios/#samplecode/KeyboardAccessory/Introduction/Intro.html
Here's the code I ended up with. I'm not worrying about the keyboard hiding, since in my view, the keyboard should never hide.
- (void)viewWillAppear:(BOOL)flag
{
[super viewWillAppear:flag];
// Listen for the keyboard to show up so we can get its height
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
// Set focus on the text view to display the keyboard immediately
[self.textView becomeFirstResponder];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
/*
Reduce the size of the text view so that it's not obscured by the keyboard.
*/
NSDictionary *userInfo = [notification userInfo];
// Get the origin of the keyboard when it's displayed.
NSValue* keyboardFrame = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
// Get the top of the keyboard as the y coordinate of its origin in self's view's
// coordinate system. The bottom of the text view's frame should align with the
// top of the keyboard's final position.
CGRect keyboardRect = [keyboardFrame CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
// Set the text view's frame height as the distance from the top of the view bounds
// to the top of the keyboard
CGFloat keyboardTop = keyboardRect.origin.y;
CGRect newTextViewFrame = self.view.bounds;
newTextViewFrame.size.height = keyboardTop - self.view.bounds.origin.y;
self.textView.frame = newTextViewFrame;
}
You can get the keyboard size like so :
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardIsUp:) name:UIKeyboardDidShowNotification object:nil];
- (void)keyboardIsUp:(NSNotification *)notification{
CGSize keyboardSize = [self.view convertRect:[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] toView:nil].size;
NSLog(#"%f", keyboardSize.height);
}
[EDIT] Landscape mode
I tried it on the iPas Simulator and it return 264 in portrait mode for a QWERTY keyboard but when you start the app or rotate to landscape mode it returns 1024. So you might need to ask for the width instead of the height in landscape mode...
[EDIT]
Thanks to rob mayoff's comment there is no problem with the landscape mode anymore
[EDIT]
This is not the best way of doing it, but that gives an idea. I'll take a look back at it later
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
CGSize size = [self.view convertRect:self.view.frame toView:nil].size;
CGFloat width = size.width;
CGFloat height = 40;
CGFloat x = 0;
CGFloat y = size.height+40;
aboveKBView = [[[UIView alloc] initWithFrame:CGRectMake(x, y, width, height)] autorelease];
[aboveKBView setBackgroundColor:[UIColor greenColor]];
[self.view addSubview:aboveKBView];
}
- (void)keyboardWillHide:(NSNotification *)notification{
[aboveKBView setHidden:YES];
}
- (void)keyboardWillShow:(NSNotification *)notification{
NSLog(#"keyboardIsUp");
CGSize keyboardSize = [self.view convertRect:[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] toView:nil].size;
CGSize size = [self.view convertRect:self.view.frame toView:nil].size;
CGFloat width = size.width;
CGFloat height = 40;
CGFloat x = 0;
CGFloat y = size.height-(keyboardSize.height+height);
[aboveKBView setFrame:CGRectMake(x, y, width, height)];
[aboveKBView setHidden:NO];
}
I find this page always quite helpful - it shows all important sizes, so it's easy to calculate the size you need:
http://www.idev101.com/code/User_Interface/sizes.html
Try this
in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
and add these methods.
- (void) keyboardWillShow: (NSNotification*) aNotification;
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect rect = [[self view] frame];
rect.origin.y -= 60;
[[self view] setFrame: rect];
[UIView commitAnimations];
}
- (void) keyboardWillHide: (NSNotification*) aNotification;
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect rect = [[self view] frame];
rect.origin.y += 60;
[[self view] setFrame: rect];
[UIView commitAnimations];
}
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 UIViewController that has an image view and a toolbar. I would like the toolbar to rotate, but the imageview to stay as it is. Is this possible?
Yes this is possible, but requires manual handling of rotate events.
In viewDidLoad, add
// store the current orientation
currentOrientation = UIInterfaceOrientationPortrait;
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector: #selector(receivedRotate:) name: UIDeviceOrientationDidChangeNotification object: nil];
if(currentOrientation != self.interfaceOrientation) {
[self deviceInterfaceOrientationChanged:self.interfaceOrientation];
}
and don't forget to deregister events when the controller is removed.
Then add a method for rotates:
// This method is called by NSNotificationCenter when the device is rotated.
-(void) receivedRotate: (NSNotification*) notification
{
NSLog(#"receivedRotate");
UIDeviceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];
if(interfaceOrientation != UIDeviceOrientationUnknown) {
[self deviceInterfaceOrientationChanged:interfaceOrientation];
} else {
NSLog(#"Unknown device orientation");
}
}
and finally the rotate method
- (void)deviceInterfaceOrientationChanged:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == currentOrientation) {
NSLog(#"Do not rotate to current orientation: %i", interfaceOrientation);
} else if(interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
NSLog(#"Do not rotate to UIInterfaceOrientationPortraitUpsideDown");
} else if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
NSLog(#"Do not rotate to UIInterfaceOrientationLandscapeLeft");
} else {
if(!isRotating)
{
isRotating = YES;
if(currentOrientation == UIInterfaceOrientationPortrait && interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"Rotate to landscape");
// rotate to right top corner
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
// do your rotation here
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDoneShowCaption:finished:context:)];
[UIView commitAnimations];
} else if(currentOrientation == UIInterfaceOrientationLandscapeRight && interfaceOrientation == UIInterfaceOrientationPortrait) {
// etc
}
isRotating = NO;
} else {
NSLog(#"We are already rotating..");
}
}
currentOrientation = interfaceOrientation;
}
Note that I do not allow for rotates in some directions, you might.
In addition, you need to make your components resizable / able to rotate.
Edit Consider using block-based animations instead and set the isRotation = NO in the completion block.
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];
}
}