iOS: Adding child view controller does not show child's components - ios

There are two view controllers, MainViewController and ChildViewController, I want to add ChildViewController to MainViewController and this is my code:
MainViewController.swift
class MainViewController: UIViewController {
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.add(ChildViewController(), in: containerView)
}
}
ChildViewController.swift
class ChildViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("ChildViewController is loaded")
}
}
UIViewController+Ext.swift
extension UIViewController {
func add(_ child: UIViewController, in container: UIView) {
addChild(child)
container.addSubview(child.view)
child.view.frame = container.bounds
child.didMove(toParent: self)
}
func add(_ child: UIViewController) {
add(child, in: view)
}
func remove(from view: UIView) {
guard parent != nil else {
return
}
willMove(toParent: nil)
removeFromParent()
view.removeFromSuperview()
}
func remove() {
remove(from: view)
}
}
Storyboard
Output:
"ChildViewController is loaded" appears in the terminal but the UI components are not loaded.

self.add(ChildViewController(), in: containerView)
You are creating a ChildViewController instance programatically instead of getting it from the storyboard.
if let childViewController = self.storyboard?.instantiateViewController(withIdentifier: "ChildViewController") {
self.add(ChildViewController(), in: containerView)
}

Related

SplitView with TabBar with SwiftUI does not extend to the bottom of the view

So I am trying to display a splitView with a tabBar but the NavigationView does not stretch all the way to the bottom. Is there something I am missing?
here is the code I am using:
import Foundation
import SwiftUI
protocol SettingsCoordinatorInput: ManagedCoordinator {
}
class SettingsCoordinator: ManagedCoordinator, SettingsCoordinatorInput {
var navigationController = UINavigationController()
weak var viewModel: SettingsViewModel?
lazy var viewController: UIHostingController<SettingsSplitView> = {
let viewModel = SettingsViewModel(coordinator: self)
self.viewModel = viewModel
return UIHostingController(rootView: SettingsSplitView())
}()
override func topController() -> UIViewController? {
return viewController
}
convenience init(delegate: ManagedCoordinator) {
self.init()
self.delegate = delegate
}
override func start() {
navigationController.viewControllers = [viewController]
}
#objc private func close() {
finish()
}
override func finish() {
super.finish()
viewController.navigationController?.dismiss(animated: true, completion: nil)
}
}
and the result is like this:

i want to triger navigationcontroller when i press button in UIView class

I want to trigger Navigation controller to some other screen when i press the button in UIView class. How can i do this?
//Code for UIView Class in Which Button Iboutlet is created
import UIKit
protocol ButtonDelegate: class {
func buttonTapped()
}
class SlidesVC: UIView {
var delegate: ButtonDelegate?
#IBAction func onClickFinish(_ sender: UIButton) {
delegate?.buttonTapped()
}
#IBOutlet weak var imgProfile: UIImageView!
}
//ViewController Class code in Which Button Protocol will be entertained
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
var slidesVC = SlidesVC()
override func viewDidLoad() {
super.viewDidLoad()
slidesVC = SlidesVC()
// add as subview, setup constraints etc
slidesVC.delegate = self
}
extension BaseVC: ButtonDelegate {
func buttonTapped() {
self.navigationController?.pushViewController(SettingsVC.settingsVC(),
animated: true)
}
}
A more easy way is to use typealias. You have to write code in 2 places. 1. your viewClass and 2. in your View Controller.
in your SlidesView class add a typealias and define param type if you need otherwise leave it empty.
class SlidesView: UIView {
typealias OnTapInviteContact = () -> Void
var onTapinviteContact: OnTapInviteContact?
#IBAction func buttonWasTapped(_ sender: UIButton) {
if self.onTapinviteContact != nil {
self.onTapinviteContact()
}
}
}
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let slidesView = SlidesView()
slidesView.onTapinviteContact = { () in
// do whatever you want to do on button tap
}
}
You can use the delegate pattern to tell the containing ViewController that the button was pressed and let it handle whatever is needed to do next, The view doesn't really need to know what happens.
A basic example:
protocol ButtonDelegate: class {
func buttonTapped()
}
class SomeView: UIView {
var delegate: ButtonDelegate?
#IBAction func buttonWasTapped(_ sender: UIButton) {
delegate?.buttonTapped()
}
}
class ViewController: UIViewController {
var someView: SomeView
override func viewDidLoad() {
someView = SomeView()
// add as subview, setup constraints etc
someView.delegate = self
}
}
extension ViewController: ButtonDelegate {
func buttonTapped() {
self.showSomeOtherViewController()
// or
let vc = NewViewController()
present(vc, animated: true)
}
}

Call function from child to parent in Swift

I am using xlpagertabstrip and I have a parent view controller which has two children (child1, child2).
In my parent view controller, I show a UIActivityViewIndicator but I want to know how to hide that indicator in my child1.
This is my code:
ParentViewController:
override func viewDidLoad() {
showActivityIndicator()
super.viewDidLoad()
}
func showActivityIndicator() {
//code related to titleview
navigationItem.titleView = titleView
}
func hideActivityIndicator() {
navigationItem.titleView = nil
}
Child1ViewController:
override func viewDidLoad() {
super.viewDidLoad()
call_api()
}
func call_api(){
//code related to api
//if api is ok, I call hideActivityIndicator()
let pctrl = ParentViewController()
pctrl.hideActivityIndicator()
}
But that code does not work. How can I solve that?
Just pass hideActivityIndicator() from the parent to the child and call it when necessary. So whenever you create your child controller do this:
// Parent Controller
childVC.someMethodFromParent = hideActivityIndicator
And in your ChildController do this:
// Child Controller
internal var someProperty: (() -> Void)!
override func viewDidLoad() {
super.viewDidLoad()
call_api()
}
func call_api(){
//code related to api
//if api is ok, I call hideActivityIndicator()
someMethodFromParent()
}
This should work
How about having a ChildViewControllerDelegate? Something like:
class ParentViewController {
func someFunc(){
...
childVC.delegate = self
...
}
}
extension ParentViewController: ChildViewControllerDelegate {
func childViewControllerDidFinishApiCall() {
hideActivityIndicator()
}
}
protocol ChildViewControllerDelegate: class {
func childViewControllerDidFinishApiCall()
}
class ChildViewController {
weak var delegate: ChildViewControllerDelegate?
func call_api(){
//code related to api
let pctrl = ParentViewController()
delegate?.childViewControllerDidFinishApiCall()
}
}

Click on the addsubview event button

I have a button in a subview called UIViewControllerB. Someone who taught me how to capture click event in UIViewControllerB will add a new view to UIView in UIViewcontroller A under string as my code.
This is the button in ViewControllerB displayed in UIView in UIViewController A
#IBAction func button_complate(sender: AnyObject) {
NSLog("aaa", "bbb")
}
Here is the UIViewControllerA containing UIView
#IBOutlet weak var addview: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
try code:
class UIViewControllerA: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func addView(/*param */) {
// do something
}
// when push to UIViewControllerB set install for viewcontrollerA
private func goToScreenB(){
let viewB = UIViewControllerB()
viewB.viewcontrollerA = self
self.navigationController?.pushViewController(viewB, animated: true)
}
}
class UIViewControllerB: UIViewController {
// In UIViewControllerB create a install of UIViewControllerA
var viewcontrollerA : UIViewControllerA?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func button_complate(sender: AnyObject) {
self.viewcontrollerA?.addView()
}
}

Changing the layout of an AlertController

I have used the following code to try and change the layout of a UIAlertController using a nib however the dialog just shows up and looks the same each time regardless of the nib specified, it looks like a translucent grey box, at the bottom of my screen.
class AlertDialogViewController: UIViewController {
var message: String = ""
override init() {
super.init(nibName: "SignUpViewController", bundle: nil)
//Below two lines are important for custom transitions.
transitioningDelegate = self
modalPresentationStyle = .Custom
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
//Other code for your dialog controller
// .
// .
// .
}
extension AlertDialogViewController : UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 0.5 //Add your own duration here
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
//Add presentation and dismiss animation transition here.
}
}
extension AlertDialogViewController : UIViewControllerTransitioningDelegate {
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
}
extension UIViewController {
func showAleartWithMessage(message: String) {
var ad = AlertDialogViewController()
ad.message = message
presentViewController(ad, animated: true, completion: nil)
}
}
You can't
The UIAlertController class is intended to be used as-is and does not
support subclassing. The view hierarchy for this class is private and
must not be modified.
Edit: Relevant code to what I said in comment is added
Imagine you want a dialog box with a UILable and two UIButtons instance
class CustomView : UIView {
var commentLabel: UILable!
var okayButton: UIButton!
var cancelButton: UIButton!
init(frame: CGRect) {
super.init(frame: frame)
commentLabel = UILabel()
okayButton = UIButton.buttonWithType(.Custom)
cancelButton = UIButton.buttonWithType(.Custom)
// TODO: Configuration such target, action, titleLable, etc. left to the user
[commentLabel, okayButton, cancelButton].map { self.addSubview($0) }
}
#IBAction func okayButtonAction(sender: AnyObject) {
// TODO: Complete implementation
}
#IBAction func okayButtonAction(sender: AnyObject) {
// TODO: Complete implementation
}
}
class CustomAlertDialogViewCongroller : UIViewController {
override func loadView() {
self.view = CustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
}
}
// In the view controller that you want to present that alert dialog. Let's call it viewController
let customAlertDialogViewController = CustomAlertDialogViewCongroller()
customAlertDialogViewController.modalPresentationStyle = .UIModalPresentationFormSheet
customAlertDialogViewController.modalTransitionStyle = .CoverVertical
viewController.presentViewController(customAlertDialogViewController, animated: true, completion: nil)

Resources