第二次加载时视图控制器未收到-shouldAutorotateToInterfaceOrientation:消息?

3
我有一个UIViewController,用于控制应用程序中查看图像的“弹出”视图。它支持自动旋转,因为它会自动调整图像大小以适应不同的方向。这个功能非常完美,但只有在我初始化并显示视图控制器的第一次才有效。当它关闭时,我会从我的视图层次结构中删除UIView并释放视图控制器,但下一次实例化并添加到我的视图层次结构时,它停止接收-shouldAutorotateToInterfaceOrientation消息,而手机被旋转了。以下是我如何实例化和显示它:
popupVC = [[PopupVC alloc] init];
[popupVC viewWillAppear:NO];
[[[UIApplication sharedApplication] keyWindow] addSubview:popupVC.view];
[popupVC viewDidAppear:NO];

这是我完成时如何删除/释放它的方法:
[popupVC viewWillDisappear:NO];
[popupVC.view removeFromSuperview];
[popupVC viewDidDisappear:NO];
[popupVC release];
popupVC = nil;

我尝试循环遍历[[UIApplication sharedApplication] keyWindow]的子视图,以查看我的弹出视图是否不在顶部,但它总是在顶部。而且每次都有不同的地址,所以我知道它是视图控制器类的不同实例。
如请求的那样,这里是PopupVC中完整的loadView方法:
- (void)loadView {

    UIView *myView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
    myView.backgroundColor = self.overlayColor;
    myView.autoresizesSubviews = NO;
    myView.hidden = YES;
    myView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    self.view = myView;
    [myView release];

    _isVisible = NO;

    UIView *myMaskView = [[UIView alloc] initWithFrame:self.view.bounds];
    myMaskView.backgroundColor = [UIColor clearColor];
    myMaskView.clipsToBounds = YES;
    myMaskView.hidden = YES;
    myMaskView.autoresizesSubviews = NO;
    myMaskView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:myMaskView];
    self.imageMaskView = myMaskView;
    [myMaskView release];

    UIImageView *myImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
    myImageView.center = self.view.center;
    myImageView.hidden = NO;
    myImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleHeight;
    [self.imageMaskView addSubview:myImageView];
    self.imageView = myImageView;
    [myImageView release];

    UIButton *myImageButton = [UIButton buttonWithType:UIButtonTypeCustom];
    myImageButton.frame = self.view.frame;
    myImageButton.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleHeight;
    [myImageButton addTarget:self action:@selector(clickImage:) forControlEvents:UIControlEventTouchUpInside];
    [self.imageMaskView addSubview:myImageButton];
    self.imageButton = myImageButton;

    UIActivityIndicatorView *myActivityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    myActivityView.hidden = YES;
    [self.view addSubview:myActivityView];
    myActivityView.center = self.view.center;
    self.activityView = myActivityView;
    [myActivityView release];
}

你什么时候设置视图控制器?此外,我认为除非整个目的是防止动画,否则不需要显式调用viewWillAppear: - Gordon Seidoh Worley
我在 UITableViewDelegate 方法中设置了它,当用户选择要显示的图像时。我的 PopupVC -loadView 方法设置视图及其使用的子视图。我养成了一个习惯,在发现我的 UITabBarController 不起作用,除非发送消息给它们之后,明确调用 -viewWillAppear:。只是一个习惯吧。 - pix0r
你不应该自己调用那些viewWillAppear/viewDidAppear方法。我认为你需要重新考虑如何初始化和清理你的弹出式VC。 - Ben Scheirman
3个回答

6

我认为这可能是新的操作系统3.0中的一个缺陷。解决此问题的方法是在打开beginGeneratingDeviceOrientationNotifications后使用NSNotificationCenter。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

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

-(void) receivedRotate: (NSNotification *) notification {
    DebugLog(@"ORIENTATION CHANGE");

    UIDeviceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];

        if(interfaceOrientation == UIDeviceOrientationPortrait) {
            self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(0));
            self.view.bounds = CGRectMake(0, 0, 320, 480);
        }
        else if(interfaceOrientation == UIDeviceOrientationLandscapeLeft) {
            self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
            self.view.bounds = CGRectMake(0, 0, 480, 320);
        }
        else if(interfaceOrientation == UIDeviceOrientationLandscapeRight) {
            self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(-90));
            self.view.bounds = CGRectMake(0, 0, 480, 320);
        }
}

#define degreesToRadians(x) (M_PI * (x) / 180.0) - user246672

6
shouldAutorotateToInterfaceOrientation处理程序不是响应旋转事件的自定义代码的地方。它的目的只是告诉操作系统您的视图控制器可以旋转。如果您想要编写自定义代码来处理旋转事件,您应该覆盖-didRotateFromInterfaceOrientation或其他类似的回调方法,具体取决于您的需求:
  • willRotateToInterfaceOrientation:duration:
  • willAnimateRotationToInterfaceOrientation:duration:
  • didRotateFromInterfaceOrientation:
  • willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
  • didAnimateFirstHalfOfRotationToInterfaceOrientation:
  • willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
请参阅开发者文档中的自动旋转视图

好的观点 - 虽然我在这里没有响应事件,但我正在错误地调试它。感谢您指出这一点。 - pix0r
尽管现在我看到-didRotateFromInterfaceOrientation:中有一些调试代码,但它也没有被触发。 - pix0r
你可以尝试让你的视图控制器重写 canBecomeFirstResponder 方法并返回 YES,在 viewDidAppear:animated 中调用 [self becomeFirstResponder],在 viewWillDisappear:animated 中调用相应的 [self resignFirstResponder]。这样做有什么不同吗? - Jason Jenkins
很遗憾 - 我的视图控制器从未收到 -canBecomeFirstResponder:。 (但听起来很有前途!) - pix0r
你的视图控制器的视图是如何创建的?你能分享一下在 PopupVC 的 loadView 方法中的代码吗?此外,你的视图是否占据整个屏幕,还是某种模态弹出窗口覆盖在其他视图上方? - Jason Jenkins
视图覆盖整个屏幕。我已经从PopupVC(请参见原始问题)添加了loadView方法。 - pix0r

0

我的问题是,我可以获取rootViewController的旋转事件,但是一旦我启动第二个viewController,它就不会收到除了运动(摇晃)和触摸之外的任何信号。这是否与原始帖子相同 - 它肯定是相似的?

我按照上面的建议进行了跟进,但我没有正确编码选择器,因此当我尝试旋转时它会抛出异常。同时,我在网上找到了这个讨论,证实了问题是在3.0中引入的。 链接文本


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