将另一个视图控制器的视图添加为子视图

时间:2012-12-19 03:56:04

标签: ios

我正在尝试获取弹出效果,并希望在另一个视图控制器中设计弹出视图,以便我可以使用xib来执行此操作。

当我使用presentViewController或pushViewController并将背景设置为透明时,我最终会看到Window的背景颜色。

我尝试使用此代码将子视图添加到导航控制器的视图中,这样我就可以让信息视图覆盖整个屏幕,并带有透明背景。我也有标签栏来掩盖。

InfoVC *vc = [[InfoVC alloc] initWithNibName:@"InfoVC" bundle:nil];
[self.navigationController.view addSubview:vc.view];

我的问题出在我的InfoVC里面,当我试图解雇它时,应用程序会因某些EXC_BAD_ACCESS消息而崩溃:

[self.view removeFromSuperview];

编辑:

我找到了一种方法来阻止它崩溃,但将InfoVC设置为MainVC中的属性。我认为崩溃的原因是当我在InfoVC内部的操作中调用“self.view”时,它不知道self是MainVC中的InfoVC。

4 个答案:

答案 0 :(得分:2)

InfoVC *vc = [[InfoVC alloc] initWithNibName:@"InfoVC" bundle:nil];
[self.navigationController.view addSubview:vc.view];

不不不不。永远不要那样做。

为了将视图控制器的视图放在另一个视图控制器的视图中(或者之后将其移除),如果没有内置工具来执行此操作(UISplitViewController的方式),您必须遍历精心设计的舞蹈是,或导航控制器管理在其中推送和弹出的视图控制器的视图的方式。)

阅读客户容器控制器。我书中的一个例子是:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch19p556containerController/p476containerController/ViewController.m

答案 1 :(得分:1)

您是否应该使用以下内容从超级视图中删除视图?

[vc.view removeFromSuperview];

答案 2 :(得分:1)

您永远不会有UIView删除它的子视图,子视图本身必须从其超级视图中删除自己。您可以轻松遍历子视图并将其删除,如此

for (UIView *view in vc.view.subviews) {
  [view removeFromSuperview];
}

参考文件: http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html

答案 3 :(得分:1)

在出现“模态”呈现的视图控制器后,将删除现在呈现的视图控制器下的视图;这样可以节省内存,并简化渲染。但是,在您的情况下,您最终还会看到“模态”呈现视图背后的窗口。

自然而且看似合乎逻辑的下一步是简单地采用一个视图控制器的视图并将其塞入另一个视图控制器视图中。但是,正如您所发现的,这是有问题的。由于视图层次结构安全地保留了新插入的视图,因此它是安全的,但是新的视图控制器不是那么幸运,它很快就会被释放。因此,当这个新视图试图联系其控制器时,您将获得EXC_BAD_ACCESS并崩溃。正如您所发现的,一种解决方法是简单地让原始视图控制器保持对新视图控制器的强引用。这可以工作......很糟糕。您仍然很有可能获得UIViewControllerHierarchyInconsistencyException

当然,如果您只想添加在IB中创建的小视图,则不需要将视图控制器用作“File's Owner”,并且有许多示例可以创建视图实例一个xib文件。

这里更有趣的问题是,“苹果会怎样做?” Apple一直认为视图控制器是封装工作单元的正确控制器。例如,他们的TWTweetComposeViewController,你呈现它,它似乎浮动。 如何?

我想到的第一种实现这一目标的方法是拥有一个不清楚的明确背景。也就是说,在呈现的视图控制器出现之前创建屏幕的图像,并在移除呈现视图之前将其设置为背景。例如(以下说明):

<强> QuickSheetViewController.xib

enter image description here

<强> QuickSheetViewController.h

#import <UIKit/UIKit.h>
@interface QuickSheetViewController : UIViewController
- (IBAction)dismissButtonPressed:(id)sender;
@end

<强> QuickSheetViewController.m

#import "QuickSheetViewController.h"
#import <QuartzCore/QuartzCore.h>
@implementation QuickSheetViewController {
    UIImage *_backgroundImage;
}
-(void)renderAndSaveBackgroundImageFromVC:(UIViewController *)vc{
    UIGraphicsBeginImageContext(vc.view.bounds.size);
    [vc.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    _backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    // save an image of the current view, and set our background to clear so we can see the slide-in.
    [self renderAndSaveBackgroundImageFromVC:self.presentingViewController];
    self.view.backgroundColor = [UIColor clearColor];
}
-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    // Time to use our saved background image.
    self.view.backgroundColor = [UIColor colorWithPatternImage:_backgroundImage];
}
-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    // Set our background to clear so we can see the slide-out.
    self.view.backgroundColor = [UIColor clearColor];
}
- (IBAction)dismissButtonPressed:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end

此示例的大部分内容取决于renderAndSaveBackgroundImageFromVC:方法。其中,我们创建一个图形上下文渲染我们将要覆盖的视图,然后创建一个UIImage到稍后(在viewDidAppear中)用作背景。

现在只需使用它:

QuickSheetViewController *newVC = [[QuickSheetViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:newVC animated:YES completion:nil];

您将在背景中看到足够长的时间以便动画发生,然后我们使用保存的图像来隐藏移除呈现视图。