2

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

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

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

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

4 回答 4

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

于 2012-12-19T04:59:20.677 回答
1

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

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

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

这里更有趣的问题是,“苹果将/如何做到这一点?” 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以供稍后(in viewDidAppear)用作背景。

现在只需像这样使用它:

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

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

于 2012-12-20T15:26:42.987 回答
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

于 2012-12-19T04:51:52.690 回答
1

您不应该使用以下内容从其超级视图中删除视图吗?

[vc.view removeFromSuperview];
于 2012-12-19T04:22:18.127 回答