UIImagePickerController (using camera as source) does autorotate on iPad2, how do i stop it? - objective-c

I am trying to write an app with some camera function, and I use an overlay view to decorate it with an image.
This is how I implement the app:
I use the UIImagePickerController to who the user what the camera takes in, and add a UIImageView onto the cameraOverlayView as a subview so that it works like this:
(image at http://www.manna-soft.com/test/uploads/UIImagePickerView-portrait.jpg)
This works fine until the iPad2 come into place... it autorotates like this and ruin the layout:
(image at http://www.manna-soft.com/test/uploads/UIImagePickerView-landscape.jpg)
The UIImagePickerController never rotates on iphone, ipod touch or the original iPad, but it does on iPad2.
the class reference of UIImagePickerContrller says that it "supports portrait mode only", but what happens is it autorotates like that....
Is there a way that I can disable the autorotation?
I tried returning NO in the method shouldAutorotateToInterfaceOrientation: of the view controller which the UIImagePickerController is presented, but it still rotates.
Thanks in advance.

The overlay view can be added to the window, and thn the window.superview can be set as cameraOverlayView.
While dismissing the ModalController the overlay view can be removed from the window.
This solution can be a little tricky to apply depending on how your app is structured.
YourAppDelegate *appDelegate = (YourAppDelegate *) [[UIApplication sharedApplication] delegate];
[appDelegate.window addSubview:overlayView];
imagePickerController.cameraOverlayView = appDelegate.window.superview;
//When dismissing the UIImagePicker
[self dismissModalViewControllerAnimated:YES];
[OverlayView removeFromSuperview];

Because UIImagePickerController derives from UINavigationController which derives from UIViewController, you can check out at "Handling View Rotations" in the UIViewController doc to see if that info helps.

You will notice that when you do this:
UIImagePickerController *camera = [UIImagePickerController new];
NSLog([self.camera shouldAutorotate] ? #"YES" : #"NO");
The result will be YES. I think by default, it is set to YES.
You can subclass UIImagePickerController and add this method to override that method:
- (BOOL)shouldAutorotate{
return NO;
}
Then instead of using UIImagePickerController, use your created subclass.
UIImagePickerSubclass *camera = [UIImagePickerSubclass new];
Hope this helps :)

You can compensate the rotation of your ipad by roatting the overlay view of your UIImagePickerController. Fisrt you have to capture the notifications using:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(notificationCallback:) name:nil object:nil];
Then use this code:
- (void) notificationCallback:(NSNotification *) notification {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if ([[notification name] isEqualToString:#"UIDeviceOrientationDidChangeNotification"]) {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
switch ( orientation ) {
case UIInterfaceOrientationLandscapeRight:
NSLog(#"LandcapeRight");
[UIView beginAnimations:#"LandscapeRight" context:UIGraphicsGetCurrentContext()];
[UIView setAnimationDuration:0.4];
m_uiCameraOverlayView.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
break;
case UIInterfaceOrientationLandscapeLeft:
NSLog(#"LandscapeLeft");
[UIView beginAnimations:#"LandcapeLeft" context:UIGraphicsGetCurrentContext()];
[UIView setAnimationDuration:0.4];
m_uiCameraOverlayView.transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(M_PI), 0, 0);
[UIView commitAnimations];
break;
case UIInterfaceOrientationPortraitUpsideDown:
NSLog(#"UpsideDown");
[UIView beginAnimations:#"UpsideDown" context:UIGraphicsGetCurrentContext()];
[UIView setAnimationDuration:0.4];
m_uiCameraOverlayView.transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI / 2), -128, -128);
[UIView commitAnimations];
break;
case UIInterfaceOrientationPortrait:
NSLog(#"Portrait");
[UIView beginAnimations:#"Portrait" context:UIGraphicsGetCurrentContext()];
[UIView setAnimationDuration:0.4];
m_uiCameraOverlayView.transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(M_PI / 2), 128, 128);
[UIView commitAnimations];
break;
default:
NSLog(#"????");
break;
}
}
}
}

Related

ios force device rotation

here is my code:
if ([[UIApplication sharedApplication] statusBarOrientation] != UIInterfaceOrientationLandscapeLeft) {
[appDelegate makeTabBarHidden:TRUE];
self.navigationController.navigationBarHidden = YES;
[UIView beginAnimations:#"newAlbum" context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(addResultGraph)];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:YES];
// Then rotate the view and re-align it:
CGAffineTransform landscapeTransform = CGAffineTransformMakeRotation( 90.0 * M_PI / -180.0 );
landscapeTransform = CGAffineTransformTranslate( landscapeTransform, +90.0, +90.0 );
[self.navigationController.view setTransform:landscapeTransform];
[UIView commitAnimations];
}
and with this, from a portrait mode, the new viewcontroller is shown in landscapeleft mode, and everything is ok, but my problem is: if I rotate the device from landscape mode in portrait, the statusbar appears in portrait mode and the viewcontroller remains in landscape mode....
how can I solve this?
thanks in advance!
You may re-implement shouldAutorotateToInterfaceOrientation method and do something like
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
This way you enable only left orientation and, if you rotate your device to portrait, the interface won't rotate

How to stop an UIView animation

I have several UIImageViews within a UIScrollView that I want to wiggle when the user long-presses one of them. So similar to the behavior you get when you long-press an icon in your iPad/iPhone menu.
So I have the following:
- (void)startWiggling {
for (UIImageView *touchView in [scrollView subviews]) {
[UIView beginAnimations:#"wiggle" context:nil];
[UIView setAnimationDuration:0.1];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView setAnimationRepeatCount:FLT_MAX];
//wiggle 1 degree both sides
touchView.transform = CGAffineTransformMakeRotation();
touchView.transform = CGAffineTransformMakeRotation(-0.0174532925);
[UIView commitAnimations];
}
}
- (void)stopWiggling {
NSLog(#"Stop wiggling");
}
This works fine. The issue is... How can I make it stop wiggling after the user has pressed a button? I have a button and connected it etc and it's reaching the stopWiggling method, so that's fine. But so...
How do I remove the UIView animation from these UIImageViews?
Can I bind this action to the user pressing the home button on their device?
#import <QuartzCore/QuartzCore.h>
then
[myView.layer removeAllAnimations];
or
[self.view.layer removeAllAnimations];

How do I stop a modal view from disappearing when rotating on iPad?

I'm using willRotateToInterfaceOrientation to swap views when my iPad rotates. If I have a modal view or an alert view open when my device rotates and swaps views, the view swaps and the alert disappears and does not reappear, even if the alert is "presented" again later.
Edit:
I've narrowed this problem a bit. When a modal view is presented with UIModalPresentationFullScreen, the modal view "survives" rotations.
What can I do to fix this?
Here is my implementation of willRotateToInterfaceOrientation:
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
//
// Load an alternate view depending on the orientation
//
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
[UIView beginAnimations:#"" context:nil];
[self setView:theLandscapeView];
self.view.bounds = CGRectMake(0, 0, 1024, 768);
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (-90));
[UIView commitAnimations];
}else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[UIView beginAnimations:#"" context:nil];
[self setView:theLandscapeView];
self.view.bounds = CGRectMake(0, 0, 1024, 768);
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (90));
[UIView commitAnimations];
}else if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
[UIView beginAnimations:#"" context:nil];
[self setView:thePortraitView];
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (0));
self.view.bounds = CGRectMake(0, 0, 768, 1024);
[UIView commitAnimations];
}else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
[UIView beginAnimations:#"" context:nil];
[self setView:thePortraitView];
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (180));
self.view.bounds = CGRectMake(0, 0, 768, 1024);
[UIView commitAnimations];
}
}
If I were solving this problem, I would do one of the following
Add the alternate views to a parent view, and not change the view property
Create a design for the views that does not require a full view swap, but rearranges or hides subelements of the view.
Present any modal from the root ViewController of the hierarchy
I would work very hard not to swap out the view entirely for the sake of orientation. It seems like something that will continue to present problems even after you have solved this one.
If you swap views, you should also swap modal views I think.
For example, if you present popover controller - it'll automatically dismissed and then appeared with UI rotation.
Here's an idea: keep you main view constant, but change the subview to your portrait or landscape view. something like:
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
// Remove the current subview from the main view
if (self.view.subviews.count) {
[self.view.subviews objectAtIndex:0] removeFromSuperview];
}
// Use your if-else block, but change [self setView:] for [self.view addSubview:]
}
So now when you create your modal, it will be linked to your controller, which now has a constant main view.
Note that I didn't test this, as I'm getting my head back into coding after two weeks off...
Good luck!

iPhone SDK: Orientation (Landscape and Portrait views)

Okay, I've got my normal app which is in portrait mode. I can force my app to go to landscape mode for a view (using navigationcontroller and viewcontroller) like this:
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
But then when I go back to the main menu (tableview) it goes straight back to portrait. I try this code:
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
But that doesn't work..
Any ideas?
Take a look at the function shouldAutorotateToInterfaceOrientation: in the UIViewController class. This function returns YES if the orientations are supported by your UIView. If you return YES only to the landscape orientation, the iPhone will automatically be put in that orientation.
The following code should do it. Put it in the UIViewController that controls the view that you want to put in landscape mode.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscape);
}
To get this to work, I added this to the rootviewcontroller:
- (void)viewWillAppear:(BOOL)animated {
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
}
This seems to be working now.
Here's what I'm doing to do this:
first, put this define at the top of your file, right under your #imports:
#define degreesToRadian(x) (M_PI * (x) / 180.0)
then, in the viewWillAppear: method
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
if you want that to be animated, then you can wrap the whole thing in an animation block, like so:
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
self.view.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
[UIView commitAnimations];
Then, in your portrait mode controller, you can do the reverse - check to see if its currently in landscape, and if so, rotate it back to Portrait.
You need to edit your Info.plist file to add the UIInterfaceOrientation key with the appropriate value (UIInterfaceOrientationLandscapeRight or UIInterfaceOrientationLandscapeLeft).
You can't use this private API.
There is a solution to do that : it's to use a view controller and adding its view to the window. then in that controller you force landscape in the shouldAutorotate... methode. It works fine, but be sure it's necessary for your project to use that, because it's not very smart  to force the user to turn his iPhone. By the way, here is an example code if you need it.
http://www.geckogeek.fr/iphone-forcer-le-mode-landscape-ou-portrait-en-cours-dexecution.html

getting a view controller to disappear

I'm trying out a multiple view application, but I can't seem to get the first view controller to go away when I bring in the new view controller. I'm laying the second (coming) view controller at index 0, and it's just placing it in the background. I thought the [going.view removeFromSuperview] would remove the original viewcontroller, but that's not what is happening...
UIViewController *coming = nil;
UIViewController *going = nil;
UIViewAnimationTransition transition;
if (answer == YES)
{
coming = boyController;
going = getInfoController;
transition = UIViewAnimationTransitionFlipFromLeft;
}
else
{
coming = girlController;
going = getInfoController;
transition = UIViewAnimationTransitionFlipFromLeft;
}
NSLog(child);
[UIView setAnimationTransition:transition forView: self.view cache:YES];
[coming viewWillAppear:YES];
[going viewWillDisappear:YES];
[going.view removeFromSuperview];
[self.view insertSubview:coming.view atIndex:0];
[going viewDidDisappear:YES];
[coming viewDidAppear:YES];
[UIView commitAnimations];
First a little refactoring:
coming = (answer ? boyController : girlController);
You can delete going and transition, as they're only used once. Then, to actually do the animation, you need to put everything in the context of an animation block.
[UIView beginAnimations:#"flipAnimation" context:NULL];
[UIView setAnimationTransition:transition forView:self.view cache:YES];
[getInfoController.view removeFromSuperview];
[self.view addSubview:coming.view];
[UIView commitAnimations];
viewWillAppear: and viewWillDisappear: are delegate methods. These will be called automatically on those views' delegates, if any. They shouldn't ever be called manually.