旋转iPhone,实例化新的UIViewController?

7
我想要实现以下功能。当用户旋转iPhone时,我希望自动实例化一个新的UIViewController,并在横向模式下向用户展示由这个新的UIViewController处理的视图。如何正确地实现这一点?
我尝试在willRotateToInterfaceOrientation和didRotateFromInterfaceOrientation方法中实例化新的控制器,但是两种方法都没有被调用!我怀疑这是因为当前控制器是通过导航控制器推入的,而该导航控制器本身由tabBarController处理。有什么建议吗?非常感谢提供简单的代码片段。
提前感谢您的帮助。
4个回答

29

更清晰的方法是不使用UIInterfaceOrientation来进行旋转。

为什么呢?因为这样你的界面或视图1就会实际旋转。这意味着在移除视图2后,你必须将其旋转回来才能重新显示它。

为了弥补这个问题,我简单地订阅了UIDeviceOrientation通知。微妙的不同之处在于,视图1无需支持自动旋转即可使此方法工作。在viewDidLoad中输入以下代码:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(detectOrientation) name:@"UIDeviceOrientationDidChangeNotification" object:nil];

然后只需定义detectOrientation方法:

-(void) detectOrientation {

     if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) || 
            ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) {

        //load view 2


    } else if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait) {

        // load view 1

    }   
}

现在你的两个视图都不需要支持自动旋转!但在加载视图2之前,你需要执行一个变换:

-(void) transformView2ToLandscape {

  NSInteger rotationDirection;
  UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];

  if(currentOrientation == UIDeviceOrientationLandscapeLeft){
    rotationDirection = 1;
  }else {
    rotationDirection = -1;
  }

  CGRect myFrame = CGRectMake(0, 0, 480, 300);
  CGAffineTransform transform = [[self view2] transform];
  transform = CGAffineTransformRotate(transform, degreesToRadians(rotationDirection * 90));
  [[self view2] setFrame: myFrame];
  CGPoint center = CGPointMake(myFrame.size.height/2.0, myFrame.size.width/2.0);
  [[self view2] setTransform: transform];
  [[self view2] setCenter: center];

}

这就是我在不支持自动旋转的视图中交换视图或旋转的方法。


1
这很有趣。我会尝试理解实际的性能,即通知传递速度更快了多少以及应用变换需要多长时间。 非常感谢。 - Massimo Cafaro
这个非常好用,特别是当你为两个方向使用两个不同的视图控制器时。 - Jinah Adam
“checked” 答案回答了这个问题,但是这个回答回答了一个(理想情况下)应该被问出来的问题。 - DBD

7
我已经在一个应用程序上实现了这种行为,关键是要确保任何父级控制器都实现shouldAutorotateToInterfaceOrientation,并且当前的视图控制器也实现它。在我的情况下,我正在使用一个选项卡控制器来拦截shouldAutorotateToInterfaceOrientation的调用,我必须覆盖选项卡控制器以使调用穿透。视图控制器的默认行为是仅以纵向模式显示。
因此,您需要强制它们允许所有方向的更改: -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; }
然后为了加载一个新的视图控制器,你应该响应:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
  if((fromInterfaceOrientation == UIInterfaceOrientationPortrait) ||
     (fromInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown))
  {    
    // Load the view controller you want to display in landscape mode...
  }
}

还可以使用:

-(void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

为了检测屏幕方向的变化。

在我的情况下,我使用didRotateFromInterfaceOrientation方法来检查上一次的方向是否为竖屏,如果是,则加载我想要在横屏模式下显示的视图。

然后我在我要加载的视图控制器中实现了相同的方法,它负责检测屏幕方向何时变回竖屏,并从视图堆栈中解除自身。

希望这能帮助你一点。

保罗


我需要子类化初始的tabBarController来添加shouldAutorotateToInterfaceOrientation方法吗?这个tabBarController已经使用IB和应用程序委托中的几行代码进行了设置。我已经按照所有步骤进行了操作,但didRotateFromInterfaceOrientation没有被调用。 - Massimo Cafaro
1
好的,我对tabBarController进行了子类化,添加了shouldAutorotateToInterfaceOrientation方法,现在一切正常了。非常感谢您的帮助。此致高考。 - Massimo Cafaro
我更喜欢完全不使用UITabBarController,而是使用一个带有UITabBar的UIViewController。 - mk12
你应该使用UIInterfaceOrientationIsPortrait函数。 - titaniumdecoy

3

实际上只有顶层控制器会被通知。您需要负责通知嵌套的控制器。

将以下内容添加到您的标签栏控制器中:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [self.selectedViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}

你不应该继承UITabBarController。 - mk12
@Mk12:为什么?这样小的覆盖会引起问题吗? - Kornel

1
你有实现 shouldAutorotateToInterfaceOrientation 吗?如果没有,那可能就是你没有收到消息的原因。

是的,我做到了。即使在 shouldAutorotateToInterfaceOrientation 中简单地返回 YES 也不起作用。 - Massimo Cafaro

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