在子视图中添加UIViewController

16

我不确定这是否是正确的关键词来搜索“将UIViewController添加到子视图中”。

如图所示,我的应用程序有两个ViewController,一个是主ViewController,另一个是第二ViewController。在主ViewController中,有一个UIView(蓝色背景)。我想在UIView中添加第二个ViewController。我有以下代码,但它没有起作用。

enter image description here

这是我的代码:

#import "ViewController.h"
#import "SampleViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *testView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    SampleViewController * sample = [[SampleViewController alloc] initWithNibName:@"SampleViewController" bundle:nil];
    sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
    [self.testView addSubview:sample.view];
} 

@end

我想知道这是否可能?我知道initWithNibName:可以在xib文件中使用,但不知道在谷歌上搜索相关术语。我只是想尝试在IOS中实验一些东西,希望你能理解我的意图。希望得到你的建议。提前致谢。

这是我的更新。

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *testView;
@property(strong,nonatomic) SampleViewController * samples;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

UIStoryboard *storyBoard = self.storyboard;
SampleViewController * sample = [storyBoard instantiateViewControllerWithIdentifier:@"SampleViewController"]; 
// SampleViewController * sample = [[SampleViewController alloc] //initWithNibName:@"SampleViewController" bundle:nil];

[self displayContentController:sample];
//commented the below line because it is not needed here, use it when you want to remove        
//child view from parent.
 //[self hideContentController:sample];

}

- (void) displayContentController: (UIViewController*) content;
{
    [self addChildViewController:content];                 // 1
    content.view.bounds = self.testView.bounds;                 //2
    [self.testView addSubview:content.view];
    [content didMoveToParentViewController:self];          // 3
}


- (void) hideContentController: (UIViewController*) content
{
    [content willMoveToParentViewController:nil];  // 1
    [content.view removeFromSuperview];            // 2
    [content removeFromParentViewController];      // 3
}

我总是遇到这个错误

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/ace/Library/Developer/CoreSimulator/Devices/035D6DD6-B6A5-4213-9FCA-ECE06ED837EC/data/Containers/Bundle/Application/EB07DD14-A6FF-4CF5-A369-45D6DBD7C0ED/Addsubviewcontroller.app> (loaded)' with name 'SampleViewController''

我认为它正在寻找一个nib文件。我这里没有实现一个nib。


通过这个链接学习:http://www.objc.io/issue-12/custom-container-view-controller-transitions.html - sanjeet
@user3818576,我根据您的需求编辑了我的答案,请使用并让我知道,如果需要更多的故障排除。 - Sandeep Ahuja
你是在使用nib文件还是故事板? - Sandeep Ahuja
故事板。我没有nib文件。 - user3818576
@user3818576,我最终编辑了你的代码,请使用并告诉我。 - Sandeep Ahuja
我差点失去了希望,但当你编辑它时。非常感谢@SandeepAhuja。谢谢,谢谢,谢谢!哈哈哈。 - user3818576
9个回答

47

您应该使用子视图控制器(Child containment)的概念,这里的MainViewController是父视图控制器,您想将子视图控制器的视图添加为Main View Controller的子视图。

添加和删除子视图控制器

//call displayContentController to add SampleViewCOntroller view to mainViewcontroller
 [self displayContentController:sampleVCObject];

// write this method in MainViewController
- (void) displayContentController: (UIViewController*) content;
{
   [self addChildViewController:content];                 // 1
   content.view.bounds = testView.bounds;                 //2
   [testView addSubview:content.view];
   [content didMoveToParentViewController:self];          // 3
}

以下是代码的作用:

它调用容器的addChildViewController:方法来添加子视图控制器。调用addChildViewController:方法还会自动调用子视图控制器的willMoveToParentViewController:方法。 它访问子视图控制器的view属性来检索视图并将其添加到自己的视图层次结构中。在添加视图之前,容器设置子视图控制器的大小和位置;容器总是选择子视图控制器内容出现的地方。虽然此示例通过显式设置框架来实现,但您也可以使用布局约束来确定视图的位置。 它显式调用子视图控制器的didMoveToParentViewController:方法来表示操作已完成。

//you can also write this method in MainViewController to remove the child VC you added before.
- (void) hideContentController: (UIViewController*) content
{
   [content willMoveToParentViewController:nil];  // 1
   [content.view removeFromSuperview];            // 2
   [content removeFromParentViewController];      // 3
}

若需要更多详细信息,请参考苹果文档: https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html

在 Interface Builder 中配置容器,无需编写代码。

为了在设计时创建父子容器关系,请像图 5-3 所示,在故事板场景中添加一个容器视图对象。容器视图对象是一个占位符对象,代表一个子视图控制器的内容。使用该视图来调整和定位子视图的根视图相对于容器中其他视图的位置和大小。

向 Interface Builder 中添加容器视图 当您加载一个带有一个或多个容器视图的视图控制器时,Interface Builder 也会加载与这些视图相关联的子视图控制器。必须在同一时间实例化父级和子级,以便创建适当的父子关系。


@user3818576 仔细阅读这份文档,可以解决你的问题,并帮助你了解今后的相关事项。 - Sandeep Ahuja
你好,Sandeep。我遇到了一个错误:“由于未捕获的异常 'NSInternalInconsistencyException' 终止应用程序,原因是'无法加载包中的 NIB 文件”。我认为这个 NIB 文件可能有问题。 - user3818576
@user3818576 请检查您在Storyboard中是否设置了StoryBoard ID为“SampleViewController”,并且交叉检查名称是否正确。还要检查它是否已添加到编译目标中。同时,请检查视图和子视图是否正确连接到它们的IBOutlets。 - Sandeep Ahuja
请看我的更新帖子。我觉得我已经走在正确的道路上了,对吧? - user3818576

13

您可以通过使用StoryBoards轻松完成此操作

  • 打开故事板并选择您的蓝色视图所在的视图控制器,在实用程序中搜索ContainerView并将其拖入您的蓝色视图中,这将自动添加一个作为您视图子视图的视图控制器。您可以在大小检查器中调整容器视图的大小。

enter image description here


你好,Raki。这对我很有效,但我想知道这是如何在程序上运作的。感谢您的回答。我从您这里学到了很多。 - user3818576
其他答案均用于程序化操作... :) - Ravi

7

我已经解决了有关第二个uiviewcontroller上的uiview问题。

以下是我使用的代码:

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
SecondViewController *sb = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:@"sb"];

sb.view.backgroundColor = [UIColor redColor];    
[sb willMoveToParentViewController:self];

[self.view addSubview:sb.view];

[self addChildViewController:sb];
[sb didMoveToParentViewController:self];

我很高兴能够帮助你。
谢谢。

3
SampleViewController * sample = [[SampleViewController alloc] initWithNibName:@"SampleViewController" bundle:nil];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);

[self addChildViewController:sample];
[self.testView addSubview:sample.view];

我这里出现了错误。很抱歉。但是当我将initwithnibname替换为init时,虽然没有错误,但我的uiview输出为空。 - user3818576
这里出现了一个错误:“由于未捕获的异常'NSInternalInconsistencyException',应用程序终止,原因是'无法在包中加载NIB文件”。我认为是nib文件的问题,对此我不太了解。抱歉,我是个新手。 - user3818576
@user3818576 是的,你需要在Xib中设置它。 - Zigii Wong

3

自从iOS5以来,您可以将childViewController添加到UIViewController中。这是一种很好的方式,可以制作更小、更可重用的viewControllers,我也非常喜欢它。

您已经非常接近了,但您只需要再添加几行代码即可。

///
 [self addChildViewController:sample];

 [self.testView addSubview:sample.view]; //you already have this..

 [sample didMoveToParentViewController:self]; 

在你的viewWillDisappear:方法或其他清理方法中,你需要进行如下清理:
//we'll need another pointer to sample, make it an iVar / property..
   [sample willMoveToParentViewController:nil];  // 1
   [sample removeFromSuperview];            // 2
   [sample removeFromParentViewController];      // 3

您可以在这里阅读有关包含子视图控制器的Apple文档:https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html

。该文档涉及到创建自定义容器视图控制器,如果需要更多帮助,请查看该链接。

你好Jef,我和其他答案一样遇到了相同的错误。我仍在努力解决这个错误。“由于未捕获的异常'NSInternalInconsistencyException',原因:'无法在包中加载NIB”。 - user3818576
你正在尝试使用的初始化程序 initWithNibName:@"SampleViewController" bundle:nil 指定了一个名为 SampleViewController.xib 的文件。如果你没有这样的文件,那么请将 nibName 参数更改为 nil。 - Jef

2

我正在尝试将UIViewController添加到子视图中,这个工作已经实现了。 在UIViewController中,我添加了2个按钮,在.h文件中:

-(IBAction)matchButtonAction:(id)sender;
-(IBAction)closeButtonAction:(id)sender;

在 .m 文件中:

-(IBAction)matchButtonAction:(id)sender
{
    NSLog(@"matchButtonAction");
}
-(IBAction)closeButtonAction:(id)sender
{
    NSLog(@"closeButtonAction");
}

但是我没有看到日志。

我需要在UIViewController instantiateViewControllerWithIdentifier上添加相同的参数?

如何解决这个问题?

我的UIViewController初始化代码如下:

AlertDialogViewController *alertDialogView = (AlertDialogViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"alertDialogView"];         
        [alertDialogView willMoveToParentViewController:self];
        [viewController.view addSubview:alertDialogView.view];
        [viewController addChildViewController:alertDialogView];
        [alertDialogView didMoveToParentViewController:viewController];

你能告诉我如何删除它吗? - python

1

由于您的视图控制器在故事板中,因此应使用instantiateViewControllerWithIdentifier从故事板中获取VC。

SampleViewController * sample = [self.storyboard instantiateViewControllerWithIdentifier:@"IdOfSampleViewController"];
sample.view.frame = CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height);
[self.testView addSubview:sample.view];

不要忘记在故事板中为SampleViewController添加标识符

我在这里没有错误,但是当我在我的第二个视图控制器中添加按钮时,我在主要部分会出现错误。 - user3818576
点击按钮时出现了什么错误?可能是因为SampleViewController正在被释放。 - Anil Varghese
您应该防止销毁sample,将其作为您的mainVC的实例变量或添加为childViewController也可以像其他人在此建议的那样工作。 - Anil Varghese
好的,谢谢。我还在努力弄清楚别人试图实现什么。关于错误,它停在应用程序委托主文件中的这里:“return UIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegate class]));”。 - user3818576
sample 设为实例变量并尝试一下。 - Anil Varghese
你好 @anil,我唯一遗漏的是这个"UIStoryboard *storyBoard = self.storyboard;",然后我结合了其他答案的代码。感谢你的帮助。 - user3818576

0
我尝试使用以下代码:
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
 secondViewController.view.frame = CGRectMake(0, 0, self.mySubView.bounds.size.width, self.mySubView.bounds.size.height);

 [self addChildViewController:secondViewController];
 [self.viewDialogSolution addSubview:secondViewController.view];

但我只看到了我的视图,而没有看到secondViewController的布局。

如何解决这个问题?

非常感谢。


好的,现在我在我的主视图中看到了UIViewController,但是如何查看UIViewController中的UIView内容? 在我的UIViewController中,我已经设置了一个带有文本的UIView,如何在我的主视图中看到它? - Giulio
我已经设置了一个视图控制器的红色背景,我看到了红色,但是我没有看到UIView?我需要链接这两个视图控制器吗?我只创建了第二个视图控制器的布局并停止了,我必须做些什么吗? - Giulio
你使用了UIStoryboard吗? - user3818576

0

让控制器:SecondViewController = self.storyboard!.instantiateViewController(withIdentifier: "secondViewController") as! SecondViewController

controller.view.frame = self.view.bounds

controller.willMove(toParent: self)

self.view.addSubview(controller.view)

self.addChild(controller)

controller.didMove(toParent: self)

控制器已经移动到父视图中


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