iosswiftuiviewcontrolleruinavigationcontrollerchildviewcontroller

Push View Controller From Child View Controller


I have an app where there is a "DadViewController" which contains a UIScrollView that has paging enabled. Each page is populated with a different UIViewController.

How Do I push a new UIViewController, from a button tap, within one of the controllers contained in the UIScrollView?

class DadView: UIView {

    let model = DadModel()

    let scrollView: UIScrollView = {
        let view = UIScrollView()
        view.isPagingEnabled = true
        // Additional setup...
        return view
    }()



    override init(frame: CGRect) {
        super.init(frame: frame)
        setupScrollView()
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }



    fileprivate func setupScrollView() {
        self.addSubview(scrollView)
        // Autolayout code to pin scrollview to all 4 sides

        let vc1 = VC1()
        scrollView.addSubview(vc1.view)
        vc1.view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)

        // Add additional view controller views with the appropriate frames...

    }
}

class DadController: UIViewController {
    var dadView: DadView!

    override func loadView() {
        super.loadView()
        dadView = DadView()
        view = dadView
    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

class VC1: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .green
    }

}

Solution

  • Change your DadView setupScrollView to accept a UIViewController instance as argument. And don't call this method in init

    class DadView: UIView {
    
        let model = DadModel()
    
        let scrollView: UIScrollView = {
            let view = UIScrollView()
            view.isPagingEnabled = true
            // Additional setup...
            return view
        }()
    
    
    
        override init(frame: CGRect) {
            super.init(frame: frame)
    //        setupScrollView()
        }
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
    
    
        fileprivate func setupScrollView(_ parentVC: UIViewController) {
            self.addSubview(scrollView)
            // Autolayout code to pin scrollview to all 4 sides
    
            let vc1 = VC1()
            vc1.view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)
            parentVC.addChild(vc1)
            scrollView.addSubview(vc1.view)
            vc1.didMove(toParent: parentVC)
    
            // Add additional view controller views with the appropriate frames...
    
        }
    }
    

    In DadViewController after creating DadView instance call setupScrollView method with self

    class DadController: UIViewController {
        var dadView: DadView!
    
        override func loadView() {
            super.loadView()
            dadView = DadView()
            dadView.setupScrollView(self)
            view = dadView
        }
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    }
    

    Then you can get parent view controller from child viewcontroller and perform push

    class VC1: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .green
        }
        @IBAction func buttonAction(_ sender: UIButton) {
            self.parent?.navigationController?.pushViewController(NewVC(), animated: true)
        }
    }