ChatGPT解决这个技术问题 Extra ChatGPT

How to add an UIViewController's view as subview

Note to googlers, this Q-A is now six years out of date!

As Micky below and others mention, this is now done on an everyday basis with Containers in iOS.

I have a ViewController which controls many subviews. When I click one of the buttons I initialize another viewcontroller and show it's view as the subview of this view. However the subview exceeds the bounds of the frame for subview and infact fills the entire screen.

What could be wrong? I presume the problem is that UIViewController's view has a frame (0,0,320,460) and hence fills the entire screen (though it receive's touch events only when touched within the subview frame bounds). How can I resize the frame to fit as subview.

In short, I need help adding a viewcontroller's view as a subview to another viewcontroller's view.

Thanks!

I would recommend against this. I did this for my first iPhone app and it turned out to be a huge bizarre mess, not to mention the fact that it broke a lot of stuff that I was trying to do with Interface Builder. In the 3.0 docs they specifically say - 1 View Controller per screen. You should do this!
Yeah even I read about it, but the problem is if I put it all in 1 viewcontroller it is whole lot of code into 1, and there are lots of IBOutlets and actions, and tables. Hence for the sake of clarity and modularity I tried to have 2 seperate viewcontrollers, with the second one just supplying view to the main viewcontroller and handling its own events. This way the main viewcontroller is somewhat cleaner. What should I be doing instead. Should I have multiple view controllers with nav controller or 1 huge view controller.
Have a look at this tutorial. It only partially works though

C
Cœur

As of iOS 5, Apple now allows you to make custom containers for the purpose of adding a UIViewController to another UIViewController particularly via methods such as addChildViewController so it is indeed possible to nest UIViewControllers

EDIT: Including in-place summary so as to avoid link breakage

I quote:

iOS provides many standard containers to help you organize your apps. However, sometimes you need to create a custom workflow that doesn’t match that provided by any of the system containers. Perhaps in your vision, your app needs a specific organization of child view controllers with specialized navigation gestures or animation transitions between them. To do that, you implement a custom container - Tell me more...

...and:

When you design a container, you create explicit parent-child relationships between your container, the parent, and other view controllers, its children - Tell me more

Sample (courtesy of Apple docs) Adding another view controller’s view to the container’s view hierarchy

- (void) displayContentController: (UIViewController*) content
{
   [self addChildViewController:content];                 
   content.view.frame = [self frameForContentController]; 
   [self.view addSubview:self.currentClientView];
   [content didMoveToParentViewController:self];          
}

Added a comment to the top of my answer on this.
Are you sure this is iOS 5? I'm getting crashes with iOS 5, but it works fine in iOS 6.
iOS 5, we are using it in our app
Thanks Micky. It turns out it's just the storyboard embed segue that isn't supported in iOS 5.
What's the role of currentClientView? I can't understand it at all in the documentation.
W
WIll Cobb

Thanks to this guys I did it http://highoncoding.com/Articles/848_Creating_iPad_Dashboard_Using_UIViewController_Containment.aspx

Add UIView, connect it to header:

@property (weak, nonatomic) IBOutlet UIView *addViewToAddPlot;

In - (void)viewDidLoad do this:

ViewControllerToAdd *nonSystemsController = [[ViewControllerToAdd alloc] initWithNibName:@"ViewControllerToAdd" bundle:nil];
    nonSystemsController.view.frame = self.addViewToAddPlot.bounds;
    [self.addViewToAddPlot addSubview:nonSystemsController.view];
    [self addChildViewController:nonSystemsController];
    [nonSystemsController didMoveToParentViewController:self];

Enjoy


The documentation states the didMoveToParentViewController should be called after addChildViewController, not before.
Thank you... great solution!
S
Steven Fisher

This answer is correct for old versions of iOS, but is now obsolete. You should use Micky Duncan's answer, which covers custom containers.

Don't do this! The intent of the UIViewController is to drive the entire screen. It just isn't appropriate for this, and it doesn't really add anything you need.

All you need is an object that owns your custom view. Just use a subclass of UIView itself, so it can be added to your window hierarchy and the memory management is fully automatic.

Point the subview NIB's owner a custom subclass of UIView. Add a contentView outlet to this custom subclass, and point it at the view within the nib. In the custom subclass do something like this:

- (id)initWithFrame: (CGRect)inFrame;
{
    if ( (self = [super initWithFrame: inFrame]) ) {
        [[NSBundle mainBundle] loadNibNamed: @"NibNameHere"
                                      owner: self
                                    options: nil];
        contentView.size = inFrame.size;
        // do extra loading here
        [self addSubview: contentView];
    }
    return self;
}

- (void)dealloc;
{
    self.contentView = nil;
    // additional release here
    [super dealloc];
}

(I'm assuming here you're using initWithFrame: to construct the subview.)


though quite a good answer at the time, this is perhaps out of date philosophy since iOS 5. See my answer below
Indeed, this was written years ago. I haven't used custom containers yet, but that seems to be the right way to solve this.
Thanks for the plug to my answer Steven :)
L
Logan

I feel like all of these answers are slightly incomplete, so here's the proper way to add a viewController's view as a subview of another viewController's view:

    [self addChildViewController:viewControllerToAdd];
    [self.view addSubview:viewControllerToAdd.view];
    [viewControllerToAdd didMoveToParentViewController:self];

If you'd like, you can copy this into your code as a snippet. SO doesn't seem to understand code replacement formatting, but they will show up clean in Xcode:

    [self addChildViewController:<#viewControllerToAdd#>];
    [self.view addSubview:<#viewControllerToAdd#>.view];
    [<#viewControllerToAdd#> didMoveToParentViewController:self];

willMove is called automatically w/ addChild. Thanks @iOSSergey

When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it.


When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it.
@iOSergey do you have a link to that? Would love to update the answer to be more correct.
I actually always used to use willMoveToParent manually as well, but when I accidentally read apple reference to this function have been surprised :) developer.apple.com/library/ios/documentation/UIKit/Reference/…:
@iOSergey - sorry, maybe I'm being dense, but I am not seeing it on there :) Mind pointing me a bit more specifically! You are not alone in always calling, and I'd like to have a good reference when people inevitably tell me to put it back in! Thanks again!
Search for "willMoveToParentViewController" on the website I linked, expend "willMoveToParentViewController" reference and under Discussion header the last paragraph :) I posted the full link, but for some reason its redirecting to the top.
r
rptwsthi

Use:

[self.view addSubview:obj.view];

r
rptwsthi

Change the frame size of viewcontroller.view.frame, and then add to subview. [viewcontrollerparent.view addSubview:viewcontroller.view]


I tried it. It doesn't work. Should I do something in the interface builder.
b
bolek

You must set the bounds properties to fit that frame. frame its superview properties, and bounds limit the frame in the view itself coordinate system.


A
Anjali jariwala

You may use PopupController for the same one the SDK which shows UIViewController as subview You may check PopupController

Here is sample code for the same

popup = PopupController
        .create(self.navigationController!)
        .customize(
            [
                .layout(.center),
                .animation(.fadeIn),
                .backgroundStyle(.blackFilter(alpha: 0.8)),
                .dismissWhenTaps(true),
                .scrollable(true)
            ]
        )
        .didShowHandler { popup in
        }
        .didCloseHandler { popup in
    }
    let container = MTMPlayerAndCardSelectionVC.instance()
    container.closeHandler = {() in
        self.popup.dismiss()
    }

    popup.show(container)

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now