在自定义容器控制器中旋转后视图未调整大小

Posted

技术标签:

【中文标题】在自定义容器控制器中旋转后视图未调整大小【英文标题】:Views Not Resizing After Rotation In Custom Container Controller 【发布时间】:2012-08-24 05:30:38 【问题描述】:

我制作了一个测试应用程序来熟悉制作自定义容器视图控制器。如果我在应用程序首次启动时或切换到不同的视图控制器后旋转设备,新视图会按照我的意图调整大小以占据整个屏幕。但是,如果我在应用程序启动后旋转,然后切换到新的视图控制器,视图将保持其纵向大小,而不是变得更短和更宽(实际上它略有不同——它从 320,460 变为 300,480)。主视图控制器在应用程序委托(无 xib)中分配初始化并设置为窗口的根视图控制器。这是我在 MasterViewController(自定义容器控制器)中的代码:

- (void)viewDidLoad 
    [super viewDidLoad];
    WelcomeController *welcome = [[WelcomeController alloc] initWithNibName:@"ViewController" bundle:nil];
    self.currentController = welcome;
    [self addChildViewController:welcome];
    [self.view addSubview:welcome.view];

    UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeft:)];
    swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.view addGestureRecognizer:swipeLeft];



- (void)swipeLeft:(UISwipeGestureRecognizer *)gesture 
    if (gesture.state == UIGestureRecognizerStateRecognized) 
        UIActionSheet *sheet =[[UIActionSheet alloc] initWithTitle:@"Select A Destination" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"welcome",@"Play",@"Scores", nil];
        [sheet showInView:self.view];
    


- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 
    switch (buttonIndex) 
        case 0:
            if ([self.currentController class] != [WelcomeController class] ) 
                WelcomeController *welcome = [[WelcomeController alloc] initWithNibName:@"ViewController" bundle:nil];
                [self addChildViewController:welcome];
                [self moveToNewController:welcome];
            
            break;
        
        case 1:
            if ([self.currentController class] != [PlayViewController class] ) 
                PlayViewController *player = [[PlayViewController alloc] initWithNibName:@"PlayViewController" bundle:nil];
                [self addChildViewController:player];
                [self moveToNewController:player];
            
            break;
        
        case 2:
            if ([self.currentController class] != [HighScores class] ) 
                HighScores *scorer = [[HighScores alloc] initWithNibName:@"HighScores" bundle:nil];
                [self addChildViewController:scorer];
                [self moveToNewController:scorer];
            
            break;
        
        case 3:
            NSLog(@"Cancelled");
            break;

        default:
            break;
    


-(void)moveToNewController:(id) newController 
    [self.currentController willMoveToParentViewController:nil];
    [self transitionFromViewController:self.currentController toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionCrossDissolve animations:^
     completion:^(BOOL finished) 
         [self.currentController removeFromParentViewController];
         [newController didMoveToParentViewController:self];
         self.currentController = newController;
     ];



- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
    return YES;//(interfaceOrientation == (UIInterfaceOrientationPortrait | UIInterfaceOrientationLandscapeLeft));

发生这种情况的任何想法(我不知道这是否意味着主视图控制器的视图没有调整大小,但是当我得到这种非调整大小的行为时,手势识别器只会在窄视图中响应,而不是结束整个屏幕)?

【问题讨论】:

我发现如果我使用 xib 文件并 alloc initWithNibName:bundle: 而不是 init,它可以正常工作。因此,它似乎与您在执行 init 时获得的视图有关。然而,当我记录视图时,无论是从普通的 init 文件还是 xib 文件,它看起来都是一样的——两者都有相同的框架和相同的 autoresize = W+H 以编程方式定义 autoresizingMask UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight 【参考方案1】:

您没有向您的子视图控制器发送旋转消息。至少不在您发布的代码中。切换子控制器后,您甚至可以使用 [self.currentController removeFromParentViewController] 从 ChildViewControllers 数组中删除前一个子控制器,因此即使您实现 - (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers,您的 ParentViewController 中始终只有一个 ChildViewController。

我已经完成了这项工作,所以我将向您粘贴我是如何做到这一点的。首先,我创建了所有的 ViewController,将它们作为子视图控制器添加到 ParentViewController。然后调用 didMoveToParentViewController: 方法。

//Controller1
Controller1 *c1 = [[Controller1 alloc] init];
c1.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c1];
[c1 didMoveToParentViewController:self];

//Controller2
Controller2 *c2 = [storyboard instantiateViewControllerWithIdentifier:@"c2"]; 
index.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c2];
[c2 didMoveToParentViewController:self];
c2.view.frame = m_contentView.frame;
[self.view addSubview:c2.view];   //It is in initial screen so set it right away
m_selectedViewController = c2;

//Controller3
Controller3 *c3 = [storyboard instantiateViewControllerWithIdentifier:@"c3"];
compare.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c3];
[c3 didMoveToParentViewController:self];

m_controllers = [NSArray arrayWithObjects:c1, c2, c3, nil];  //Hmm now i think this is not needed, I can access viewController directly from self.childViewControllers array

然后我实现了

- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers

    return YES;

使用此代码切换到子视图控制器

if (value < m_controllers.count)

    UIViewController *contentViewController = [m_controllers objectAtIndex:value];
    
    contentViewController.view.frame = m_contentView.frame;
    
    [self transitionFromViewController:m_selectedViewController toViewController:contentViewController duration:0 options:UIViewAnimationOptionTransitionNone animations:nil completion:^(BOOL finished) 
        m_selectedViewController = contentViewController;
        
     ];

这应该足够了。但是我对此有一些问题,所以我自己向不活跃的 Childs 发送轮换消息。

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

    for (UIViewController *vc in m_controllers) 
    
        if(vc != m_selectedViewController)
            [vc willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    


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

    for (UIViewController *vc in m_controllers) 
    
        if(vc != m_selectedViewController)
            [vc willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
    


- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation

    for (UIViewController *vc in m_controllers) 
    
        if(vc != m_selectedViewController)
            [vc didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    

【讨论】:

automaticallyForwardAppearanceAndRotationMethodsToChildViewController 在 ios 6 中被弃用,由 shouldAutomaticallyForwardRotationMethods 取代。但是,您不需要实现它,因为默认值为 YES。所以,这不是问题。正如我在对该问题的评论中提到的那样,我已经找到了答案。【参考方案2】:

手动添加

self.view.autoresizesSubviews = YES;

里面

- (void)viewDidLoad

它解决了这个问题,

出于某种原因,我猜故事板中的值没有被使用

【讨论】:

以上是关于在自定义容器控制器中旋转后视图未调整大小的主要内容,如果未能解决你的问题,请参考以下文章

(自动布局)容器视图调整大小但子视图不

如何避免在自定义容器(stackedViewcontroller)内的 UiNavigationcontroller 内调整 UITableView 的大小

UIViewController 的视图未由 viewWillAppear() 调整大小 [重复]

自定义表格单元格未调整大小以适合内容视图

在自定义单元格中调整 iOS 7.1 中的 UILabel 大小

获取视图大小未调整大小