查看所有内容:UIWindow子视图VS UIViewController子视图

时间:2012-01-08 00:55:28

标签: iphone xcode uiview uialertview uiwindow

为了在UIView的行为之上创建UIAlertView,我看到的最佳方法是将其放入应用窗口,即将视图添加到:

[[[UIApplication sharedApplication] delegate] window]

然而,我发现的缺点是它不会自动进行旋转。为了使其轮流,最好的方法是在当前的AppDelegate window.navigationController / rootViewController上添加视图,但是,通过这样做,它将不再是所有内容。假设当显示视图并且有一个modalViewController弹出窗口时,模态视图肯定会掩盖视图。

我的问题是,是否可以将子视图添加到最顶层的窗口支持方向?在这种情况下我需要两组Nib文件吗? UIAlertView如何结合最顶层和最顶层的魔力定向支持?当我查看UIAlertView.h时,我发现实际上有2 UIWindows,一次称为originalWindow,另一次称为dimWindow。我可以在哪里找到UIAlertView.m的源代码吗?

3 个答案:

答案 0 :(得分:15)

我发现的最佳解决方案是创建一个透明的容器视图,将该容器添加到窗口,并将警报放在容器中。然后,您可以注册UIApplicationWillChangeStatusBarOrientationNotification以接收轮换事件并转换容器;这允许您独立操作警报的框架:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
     ...
     self.container = [[UIView alloc] initWithFrame:self.window.bounds];
     [self.container addSubview:self.alertView];
     [self.window addSubview:self.container];
     [[NSNotificationCenter defaultCenter] addObserver:self 
                                              selector:@selector(statusBarWillRotate:) 
                                                  name:UIApplicationWillChangeStatusBarOrientationNotification 
                                                object:nil];
     ...
}
...
- (void)statusBarWillRotate:(NSNotification *)theNotification
{
    CGFloat rotation = 0;
    switch ([notification[UIApplicationStatusBarOrientationUserInfoKey] intValue])
    {
        case UIInterfaceOrientationLandscapeLeft:
            rotation = -M_PI_2;
            break;
        case UIInterfaceOrientationLandscapeRight:
            rotation = M_PI_2;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            rotation = M_PI;
            break;
        case UIInterfaceOrientationPortrait: 
        default:
            rotation = 0;
            break;
    }
    CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(rotation);
    CGSize rotatedSize = CGRectApplyAffineTransform(self.window.bounds, rotationTransform).size;
    [UIView animationWithDuration:[UIApplication sharedApplication].statusBarOrientationAnimationDuration
                       animations:^{
         self.container.transform = rotationTransform;
         // Transform invalidates the frame, so use bounds/center
         self.container.bounds = CGRectMake(0, 0, rotatedSize.width, rotatedSize.height);
         self.container.center = CGPointMake(self.window.bounds.size.width / 2, self.window.bounds.size.height / 2);
     }];
}

如果你真的想要,你可以创建一个全新的窗口,其windowLevel属性设置为UIWindowLevelAlert,这将保证窗口保持在所有其他视图之上,包括键盘,但是窗口管理层变得非常棘手。上述解决方案应该足以满足大多数需求。

简单地将视图控制器的视图添加到窗口的问题是,除非将视图添加到视图控制器层次结构,否则无法保证接收所有旋转和view[Will|Did][Disa|A]ppear:消息根视图控制器上的addChildViewController:

答案 1 :(得分:4)

只有UIWindow的第一个子视图会被告知方向更改。 (< iOS8)

您的问题与此问题非常相似:

Multiple views in a UIWindow

正如那里的答案所说,您可以注册方向更改通知,并以此方式处理“最佳”子视图的重新布局。

答案 2 :(得分:2)

这是一个可能的解决方案,我将通过几个步骤进行解释。

  1. 开始使用UIViewController继承的课程代替UIView,让我们说TopViewController继承的名为UIViewController的课程
  2. 由于您无法在UIView继承的类中注册设备/接口轮换,因此从TopViewController继承的UIViewController类具有响应View Rotation Events的方法。现在可以捕获旋转事件。
  3. 最后,您可以使用您在问题中提到的相同方法将TopViewController视图放在UIWindow的顶部。

    [[[[UIApplication sharedApplication] delegate] window] addSubview:(TopViewController object).view];
    
  4. 希望这会有所帮助。