Add child view controller swift
Solution 1
When I use your code, run the app, and pause the app, and look at the view hierarchy, I see the following:
(lldb) po [[UIWindow keyWindow] recursiveDescription]
<UIWindow: 0x156bdc30; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x156be750>; layer = <UIWindowLayer: 0x156aa3c0>>
| <UIView: 0x156c5440; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x156c55c0>>
| | <UIScrollView: 0x156c2740; frame = (0 0; 0 568); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x156c4d00>; layer = <CALayer: 0x156c2a80>; contentOffset: {0, 0}; contentSize: {960, 568}>
| | | <UIView: 0x156c6df0; frame = (640 0; 0 536); autoresize = W+H; layer = <CALayer: 0x156c6d80>>
| | | <UIView: 0x156c7100; frame = (320 0; 0 536); autoresize = W+H; layer = <CALayer: 0x156c70a0>>
| | | <UIView: 0x156c73f0; frame = (0 0; 0 536); autoresize = W+H; layer = <CALayer: 0x156c7390>>
| | | <UIImageView: 0x156c8bd0; frame = (0 564.5; 600 3.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x156c8c50>>
| | | <UIImageView: 0x156c9020; frame = (-3.5 32; 3.5 568); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x156c90a0>>
| | <_UILayoutGuide: 0x156c5620; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x156c5800>>
| | <_UILayoutGuide: 0x156c5c90; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x156c5d10>>
If you're not seeing your subviews there, then likely culprits include:
You may not have specified the view controller base class in your scene, and thus this code isn't being run. You can confirm this with a
println
log statement or breakpoint in side thisviewDidLoad
and make sure you're hitting this routine.You may not have hooked up the
@IBOutlet
for thescrollView
, and thusscrollView
isnil
. Confirm this by putting breakpoint inviewDidLoad
and examining thescrollView
property.
In your revised question, we can now see that the three subviews are present and appear to be the correct size. That's great.
Now the question is why you don't see anything. If you have these defined as scenes in your storyboard, you should:
Make sure the "base class" and the "storyboard identifier" is defined for each of these three child scenes; and
When your main view controller instantiates the three child view controllers, you would instantiate them from the storyboard using the storyboard identifier (in my example, I used storyboard identifiers of
A
,B
, andC
, respectively):let Avc = storyboard.instantiateViewControllerWithIdentifier("A") as AViewController let Bvc = storyboard.instantiateViewControllerWithIdentifier("B") as BViewController let Cvc = storyboard.instantiateViewControllerWithIdentifier("C") as CViewController
If you do the above and repeat the recursiveDescription
you should see your scene's subviews (e.g. the labels you added) appear in the output.
Solution 2
Use following Extension for adding ChildviewController create file Extensions.swift copy bellow code
import UIKit
extension UIViewController {
func configureChildViewController(childController: UIViewController, onView: UIView?) {
var holderView = self.view
if let onView = onView {
holderView = onView
}
addChildViewController(childController)
holderView?.addSubview(childController.view)
constrainViewEqual(holderView: holderView!, view: childController.view)
childController.didMove(toParentViewController: self)
}
func constrainViewEqual(holderView: UIView, view: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
//pin 100 points from the top of the super
let pinTop = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal,
toItem: holderView, attribute: .top, multiplier: 1.0, constant: 0)
let pinBottom = NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal,
toItem: holderView, attribute: .bottom, multiplier: 1.0, constant: 0)
let pinLeft = NSLayoutConstraint(item: view, attribute: .left, relatedBy: .equal,
toItem: holderView, attribute: .left, multiplier: 1.0, constant: 0)
let pinRight = NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal,
toItem: holderView, attribute: .right, multiplier: 1.0, constant: 0)
holderView.addConstraints([pinTop, pinBottom, pinLeft, pinRight])
}
}
User view controller
import UIKit
class MyViewControler:UIViewControler {
@IBOutlet weak var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let demoViewInstance = storyboard!.instantiateViewController(withIdentifier: "youChiledViewController_Id") as! childViewController
configureChildViewController(childController: demoViewInstance, onView: myView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Related videos on Youtube
jmcastel
Updated on April 02, 2020Comments
-
jmcastel about 4 years
I m trying to add child view controller to a containerViewController
Child are :
AViewController BViewController CViewController
I have no error but when i launch the app, i can swipe the screen, there is 3 section swiped but the A,B,C view controllers don't appeared..
This is my code, any idea ?
import UIKit class ContainerViewController: UIViewController { @IBOutlet var scrollView: UIScrollView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. // creat VC var Avc : AViewController = AViewController () var Bvc : BViewController = BViewController () var Cvc : CViewController = CViewController () // add it to the view hierarchie self.addChildViewController(Cvc) self.scrollView.addSubview(Cvc.view) Cvc.didMoveToParentViewController(self) self.addChildViewController(Bvc) self.scrollView.addSubview(Bvc.view) Bvc.didMoveToParentViewController(self) self.addChildViewController(Avc) self.scrollView.addSubview(Avc.view) Avc.didMoveToParentViewController(self) // set the frame var adminFrame : CGRect = Avc.view.frame adminFrame.origin.x = adminFrame.width Bvc.view.frame = adminFrame var BFrame : CGRect = Bvc.view.frame BFrame.origin.x = 2*BFrame.width Cvc.view.frame = BFrame // set the frame of the scrollview var scrollWidth: CGFloat = 3*self.view.frame.width var scrollHeight: CGFloat = self.view.frame.size.height self.scrollView.contentSize = CGSizeMake(scrollWidth, scrollHeight) }
Edit:
Looking at the view hierarchy, it reports the following:
<UIWindow: 0x7ff3fad19f70; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7ff3fac3efe0>; layer = <UIWindowLayer: 0x7ff3fad19740>> | <UIView: 0x7ff3fb108b90; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fb108e60>> | | <UIScrollView: 0x7ff3fac3acf0; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7ff3fb107320>; layer = <CALayer: 0x7ff3fac18e00>; contentOffset: {0, 0}; contentSize: {960, 568}> | | | <UIView: 0x7ff3fac41ed0; frame = (640 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fac28a00>> | | | <UIView: 0x7ff3fac42320; frame = (320 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fac38e10>> | | | <UIView: 0x7ff3fac42730; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ff3fac42810>> | | | <UIImageView: 0x7ff3faf020f0; frame = (0 564.5; 320 3.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x7ff3fae0df80>> | | | <UIImageView: 0x7ff3fac1c660; frame = (316.5 0; 3.5 568); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x7ff3fac39420>> | | <_UILayoutGuide: 0x7ff3fb108ec0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7ff3fb1091e0>> | | <_UILayoutGuide: 0x7ff3fb109c20; frame = (0 568; 0 0); hidden = YES; layer = <CALayer: 0x7ff3fb109d00>>
-
Rob over 9 yearsYou might want to pause the app and at the
(lldb)
prompt, enterpo [[UIWindow keyWindow] recursiveDescription]
, which will show you the frames for all of the views. It seems to me that you never setAvc.view.frame
, so I bet itsCGRectZero
. I'd suggestAvc.view.frame = self.view.bounds
before you start setting the frame ofBvc
andCvc
. -
jmcastel over 9 yearsI think the only frame witch is dysplayed is the scrollView's frame of my container, i tried your solution but it doesn't work.
-
jmcastel over 9 yearsThe (lldb) po [[UIWindow keyWindow] recursiveDescription] <UIWindow: 0x7ffbd9454b20; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7ffbd94553d0>; layer = <UIWindowLayer: 0x7ffbd9451c00>> | <UIView: 0x7ffbd9718e60; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7ffbd9719130>> | | <UIScrollView: 0x7ffbd970fdd0; frame = (0 0; 320 568);
-
Rob over 9 yearsBrilliant! So your subviews are there! But you haven't apparently added anything to those subviews, so there's nothing to see.
-
jmcastel over 9 yearsI just changed the color's background for each of them to identify the different subviews, but i can't see the different color when swipping, everything is white. I also add a label...
-
jmcastel over 9 yearsIn fact i m trying to do this github.com/lbrendanl/SwiftSwipeView with this tuto medium.com/swift-programming/…
-
Rob over 9 yearsDid you add the label and change the color programmatically or in interface builder. If the latter, you have to instantiate the three child views from the storyboard, as shown in my revised answer. If you're doing it programmatically, update your question with the code you used. And, as always, repeat that
recursiveDescription
process so you can differentiate between the label not being there vs having aframe
that makes it impossible to see (look for zero width or height values).
-
-
Rob over 9 yearsSo, when you put your breakpoint in
viewDidLoad
, and examinedscrollView
when you hit the breakpoint, it was non-nil
? -
jmcastel over 9 yearsi ve got an error in this breakpoint with po [[UIWindo keyWindow] recursiveDescription] :error: <EXPR>:1:12: error: expected ',' separator [[UIWindow keyWindow] recursiveDescription] ^ , <EXPR>:1:23: error: expected ',' separator [[UIWindow keyWindow] recursiveDescription]
-
jmcastel over 9 yearssorry im noob...i have this <UIScrollView: 0x7fd47ac17540; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7fd47ac1ea90>; layer = <CALayer: 0x7fd47ac16ac0>; contentOffset: {0, 0}; contentSize: {0, 0}>
-
jmcastel over 9 yearsOk i tried to instantiate from the storyboard but the ap crash because "doesn't contain a view controller with identifier 'A'". It s normal since i can't set the "A" identifier in the storyboard. In my storyboard i have only one view controler (ContainerViewControler class). A, B, CViewController are xib file so they are not visible ine the storyboard. Thank for your patience and sorry for my bad english..
-
Rob over 9 yearsIt's weird to use a NIB rather than putting it on your storyboard, but that's fine. If it's in a NIB, you have to instantiate your view controller from that (e.g.
let Avc = AViewController(nibName: "nibname", bundle: nil)
). -
jmcastel over 9 yearsOk i will trie to do it by putting the views in my storyboard. I just followed the tuto in fatc.
-
jmcastel over 9 yearsIt's working !! yeah !! Thank you so much master Rob !!
-
Natalia almost 8 yearsI find your answer a bit unclear - where do the contstraints come in? Could you clarify a bit what your extension intends to do and why you sugest this approach? It would help me understand how to approach this.
-
Phani Sai almost 8 years@NataliaChodelski please check above updated code for better understand
-
Takagi almost 6 years@PhaniSai I have reworked your code slightly, so there is no explicit unwrapping
holderView!
. gist.github.com/neoneye/fd01d21944b40fc7794af6c8f0591725