【问题标题】:Adding another view controller's view as subview添加另一个视图控制器的视图作为子视图
【发布时间】:2012-12-06 09:14:19
【问题描述】:

我正在尝试获得弹出效果,并希望在另一个视图控制器中设计弹出视图,以便我可以使用 xib 来做到这一点。

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

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

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。

【问题讨论】:

  • 您不需要另一个视图控制器来在 xib 中创建视图。你可以有一个只是一个视图的xib。现在,根据您对该视图的操作,您可能希望它拥有自己的控制器,但这不是必需的。
  • 一个xib就是一个视图。我想这就是我所追求的。是否有说明如何使用它的教程?
  • 你需要什么教程?只需选择“新建文件”,选择“用户界面”作为类型,然后选择“查看”。
  • 抱歉,我还是新手,但我使用 NSNib 搜索并找到了其他一些线程。我认为 xib 必须与视图控制器一起使用。

标签: ios


【解决方案1】:
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

【讨论】:

  • 我会记住这一点。我还没准备好创建自己的容器=D
  • 然后只使用一个视图并将额外的视图控制器排除在外。您可以轻松地将视图弹出和弹出其他视图。只是不要在这个过程中滥用视图控制器。
  • @RosePerrone 当本书从 iOS 5 升级到 iOS 6 时,页码发生了变化。很明显是哪个示例:github.com/mattneub/Programming-iOS-Book-Examples/blob/master/…
  • 两个链接现在都断开了。您能否将书中最重要的部分复制到您的答案中,以便您的答案不再容易受到链接失效的影响?
【解决方案2】:

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

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

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

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

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

QuickSheetViewController.xib

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];

您将通过背景看到足够长的时间以使动画发生,然后我们使用我们保存的图像来隐藏当前视图的删除。

【讨论】:

    【解决方案3】:

    你永远不能让UIView 删除它的子视图,子视图本身必须从它的父视图中删除。您可以轻松地遍历子视图并像这样删除它们

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

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

    【讨论】:

      【解决方案4】:

      您不应该使用以下方法从其父视图中删除视图吗?

      [vc.view removeFromSuperview];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多