iOS7 / iOS6应用不同部分的条件旋转(横屏/竖屏)

5
问题:我有一个应用程序,其中不同部分使用横向模式(锁定)和纵向模式(锁定)。现在我有一个可行的解决方案,但它似乎不正确,并且有自己的问题。最理想的情况是强制进行方向更改。如果需要,甚至考虑进行视图转换。
应用程序的基本流程:
- HomeView(纵向)(其中有一些子推送视图,也是纵向并锁定在那里)。 - LandscapeView(横向)(其中有5个推送的子视图,也是横向)。
注意:
- HomeView有一个指向LandscapeView的链接。 - LandscapeView可以返回到HomeView。 - 在LandscapeView子视图的末尾,它会返回到HomeView。
基本图像显示了不同视图方向的外观。 (线表示应用程序流程,图像的方向表示每个屏幕应该如何)
目前使用以下实现通过[setLockedToPortait:YES](对于纵向视图)等来调用/设置视图是否处于纵向模式或横向模式。
这会使iOS从设备旋转时查询要使用的界面方向。
现在对于进入LandscapeView的情况,我会在正常视图上方显示一个临时视图,要求使用者将其手机旋转到横向。 (从横向视图返回到HomeView时,也会显示临时视图)
因此,一旦用户旋转了设备,它将触发正确的方向,然后临时视图将隐藏。
如果此时用户将其手机旋转回纵向,则仍将锁定为横向,因此不会触发另一个视图旋转(也不会出现任何临时视图等)。
当前实现代码:
// ---------------------- NavigationController (subclass of UINavigationController)
@interface NavigationController () {
BOOL isOrientationPortrait;
}
@end


@implementation NavigationController {
       UIDeviceOrientation lastAccepted;
       UIDeviceOrientation lastKnown;
 }

-(void)setLockedToPortait:(BOOL)isLocked {
    isOrientationPortrait = isLocked;
}

-(UIDeviceOrientation) getCurrentOrientation {
UIDeviceOrientation orientate = [[UIDevice currentDevice] orientation];
if(orientate == 0) { // needed for simulator
    orientate = (UIDeviceOrientation)[UIApplication sharedApplication].statusBarOrientation;
}
return orientate;
}

// Deprecated in iOS6, still needed for iOS5 support.
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation
{
UIDeviceOrientation orientation = [self getCurrentOrientation];
[self setLastKnownOrientation:orientation];

if(isOrientationPortrait == YES) {
    if([self isLastKnownPortrait] == YES) {
        [self setLastAcceptedOrientation:orientation];
        return YES;
    } else {
        return NO;
    }
} else {
    if([self isLastKnownLandscape] == YES) {
        [self setLastAcceptedOrientation:orientation];
        return YES;
    } else {
        return NO;
    }
}
}

// iOS6/7 support
- (BOOL)shouldAutorotate
{
    // find out the current device orientation
UIDeviceOrientation orientation = [self getCurrentOrientation];
[self setLastKnownOrientation:orientation];
return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
if(isOrientationPortrait == YES) {
    if([self isLastKnownPortrait] == YES)
    {
        UIDeviceOrientation orientation = [self getCurrentOrientation];
        [self setLastAcceptedOrientation:orientation];
    }
    return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
} else {
    if([self isLastKnownLandscape] == YES)
    {
        UIDeviceOrientation orientation = [self getCurrentOrientation];
        [self setLastAcceptedOrientation:orientation];
    }
    return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight );
}
}
-(void)setLastAcceptedOrientation:(UIDeviceOrientation)orient  {
lastAccepted = orient;
}

-(void)setLastKnownOrientation:(UIDeviceOrientation)orient {
    lastKnown = orient;
}

-(BOOL)isLastKnownPortrait {
    return UIDeviceOrientationIsPortrait(lastKnown);
}

-(BOOL)isLastKnownLandscape {
    return UIDeviceOrientationIsLandscape(lastKnown);
}

-(BOOL)isLastAcceptedPortrait {
    return UIDeviceOrientationIsPortrait(lastAccepted);
}

-(BOOL)isLastAcceptedLandscape {
    return UIDeviceOrientationIsLandscape(lastAccepted);
}

当前问题:

  • 在用户从纵向模式切换到横向模式或从横向模式切换到纵向模式后,需要始终进行设备旋转。
  • 如果用户锁定了设备方向,则这根本行不通。
  • 当从横向模式返回并且用户已经将其设备旋转到纵向模式(在上一个横向视图中),纵向视图的界面将被锁定为“横向”布局,直到用户重新旋转其设备(所以目前我只是显示叠加层来旋转设备,但它已经旋转了……对用户非常烦人)。目前以上实现存在巨大问题。

希望能够做到:

  • 强制更改当前视图的方向。
  • 设置一个首选布局,用于在推送/弹出视图之间强制使用。

我在这里和Apple Dev论坛上看过很多其他解决方案,但似乎没有覆盖这个问题,或者这两个视图之间仍然存在方向bug。

感谢任何帮助或指针!没有建议将被忽略:D

-- 编辑:

感谢@leo-natan找到解决方案!

所以,不要试图强制更改视图的方向。只需推送一个新的模态视图。这会强制更改。您仍然需要以上关于管理旋转的方向代码。

因此,现在在我的HomeViewController中是:

LandscapeViewController * viewController = [[[LandscapeViewController ViewController alloc] init] autorelease];
UINib * nib = [UINib nibWithNibName:@"NavigationController" bundle:nil];
NavigationController *navController = [[nib instantiateWithOwner:nil options:nil] objectAtIndex:0];
[navController initWithRootViewController:viewController];
[self presentViewController:navController animated:YES completion:^{
    // completion
}];

因此,有必要为此模态视图重新添加一个新的导航控制器。另外请注意,'presentViewController'是推送模态视图的新方式。

实现了这个重载方法来管理视图控制器:

-(id)initWithRootViewController:(UIViewController *)rootViewController {

self = [super initWithRootViewController:rootViewController];
    if(self){

    }
return self;
}

注意:以上内容未使用storyboard。可以通过使用storyboard并以相同方式模态显示视图来解决该问题。

1个回答

7

请查看我在这里的答案(包括测试项目)

基本上,只有在以模态方式呈现视图控制器时才能强制更改方向,例如某些应用程序中的媒体播放。如果您想从仅能以纵向显示的视图控制器转换到仅以横向显示的视图控制器,则需要进行模态呈现。推送将无法起作用。


1
如果我可以的话,我会抱抱你!Modal是正确的路径。我将发布一个编程解决方案。谢谢Leo! - Danoli3
好的,只是在iOS5中进行测试。对它不起作用。有任何想法吗? - Danoli3
@Danoli3 苹果在iOS6及以上版本中显著改变了旋转处理方式。我的示例仅实现了iOS6所需的内容。请查看- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation以获取iOS5的相关信息。 - Léo Natan
是的,我不得不使用我的自定义“置于顶部”的视图,并等待用户旋转到横向模式(仅适用于iOS5)。然而,您提供的解决方案与此相结合,解决了返回纵向模式再次旋转的问题(因为该视图仍处于纵向模式)!谢谢Leo Natan!真是个传奇! - Danoli3
1
哇,太棒了!谢谢,我从未在文档中看到过这个,它非常好用! - Collin White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接