问题
Help me to solve the task - I have a viewController that is not allowed to rotate its interface:
- (BOOL)shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
But I need to rotate alertView which appears in this controller! So if user rotates the device the alertView should follow the rotation and the main interface stands still. I've tried to subscribe to notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceRotated:) name:UIDeviceOrientationDidChangeNotification object:nil];
But in my deviceRotated: I'm receiving the notification with such payload:
NSConcreteNotification 0x101dc50 {name = UIDeviceOrientationDidChangeNotification; object = <UIDevice: 0x103e640>; userInfo = {
UIDeviceOrientationRotateAnimatedUserInfoKey = 1;
}}
What is UIDeviceOrientationRotateAnimatedUserInfoKey? And how do I use to know the current interfaceOrientation? Or suggest a better way of obtaining the current orientation and rotating the alertView.
I tried to use
(BOOL)shouldAutorotateToInterfaceOrientation:UIInterfaceOrientation)toInterfaceOrientation
and
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration but these methods don't get called on iOS6 :(
Also, are there any other methods which you can use to know that device is rotating to some orientation? Thanks in advance! P.S. I know that task seems a bit silly but this is the customer claim. sorry :)
回答1:
There's a orientation variable in UIDevice that contains the current device orientation. You can use it instead of the interface orientation (that will not rotate as you already noticed).
First you subscribe to device orientation changes, a good place is on viewWillAppear and unsubscribe on viewWillDisappear:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
In this example, we indicated that we want to be called to orientationChanged: when the device rotates, so lets implement it:
#pragma mark - Orientation change events
- (void)orientationChanged:(NSNotification*)notification {
UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
// Calculate rotation angle
CGFloat angle;
switch (deviceOrientation) {
case UIDeviceOrientationPortraitUpsideDown:
angle = M_PI;
break;
case UIDeviceOrientationLandscapeLeft:
angle = M_PI_2;
break;
case UIDeviceOrientationLandscapeRight:
angle = - M_PI_2;
break;
default:
angle = 0;
break;
}
// Apply rotation
static NSTimeInterval animationDuration = 0.3;
[UIView animateWithDuration:animationDuration animations:^{
_viewToRotate.transform = CGAffineTransformMakeRotation(angle);
}];
}
回答2:
I delete the previous answer 'cause I misunderstood the problem (actually it's a very strange request but...). I suggest you to use a Container View Controller with unlimited rotation mask, then add your controller as child: the CVC forward the rotation events to children based on the following method:
- (BOOL) automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers
{
return NO;
}
So it will get all the events and forward to the child only the one you want to.
Finally the Container will manage the alert and rotate it properly.
回答3:
Since the orientation is locked to a specific position, referring to the statusbar won't be much help. My suggestion would be to use the accelerometer and change the alertView accordingly based on the received XYZ values. You can rotate the alertView by using either CGAffineTransformMakeRotation or CGAffineTransformRotate methods.
An example of using the accelerometer is the following:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
accelerationValue[0] = acceleration.x;
accelerationValue[1] = acceleration.y;
accelerationValue[2] = acceleration.z;
NSLog(@"Acceleration X-axis: %1.1f, Y-axis: %1.1f, Z-axis: %1.1f", acceleration.x, acceleration.y, acceleration.z);
}
Of course the accelerometer would need to be set up and created in the respective ViewController, but I think you get my point.
来源:https://stackoverflow.com/questions/15390359/how-to-rotate-a-view-in-controller-that-is-not-allowed-to-rotate-its-interface