Change child of iOS Container View from child interaction - ios

I have a Container View that contains a view. I want to change this view to another, calling a method of the parent view when the user interacts with an object of this child view.
How can I do this?

let say the container is a class named 'ContainerView' and it has a function called 'changeSubView'
from the child view you can call it using:
let containerView = self.superview as! ContainerView
containerView.changeSubView()

Related

How to provide an argument to a view controller in containment?

I'm trying to pass an argument to a view controller in containment:
let childVC = ChildViewController()
addChild(childVC)
childVC.view.frame = frame
view.addSubview(childVC.view)
childVC.didMove(toParent: self)
ChildViewController has multiple properties, one of which has to be passed on from the parent view controller.
I've tried a few things, but none worked:
let childVC = ChildViewController(someProperty: someProperty)
or
let childVC = ChildViewController()
childVC.someProperty = someProperty
This line:
let childVC = ChildViewController()
Is almost always wrong. That will create an empty instance of ChildViewController with no views, outlets, or actions set up.
Generally you want to instantiate a view controller from a Storboard or a nibfile.
If you are asking how you install contents in a child view controller's views, the answer is "Don't do that."
If you want your parent view controller to have a child view controller, the easiest way to do that is to put a container view on the parent view controller in IB. Then control-drag from that container view onto the view controller you want to be a child, and when prompted, select "embed segue" as the type of link you want to create.
That will cause the system to install the child view controller in the container view and hook up all the plumbing to make it work
The parent view controller's prepare(for:sender:) method will be called right after the child view controller is instantiated, but before it's views are loaded. You can put code in your prepare(for:sender:) method to pass values to the child view controller (not set it's views directly, but set properties or call methods)

ViewDidAppear not called for child view added to rootViewController

I am trying to display a child view controller over the top of all elements on screen (including navigation bars), and the only way I've found that works is to add it as a child view controller to my window's rootViewController:
guard let window = UIApplication.shared.keyWindow,
let view = window.rootViewController?.view
else { return }
window.rootViewController?.addChildViewController(attachmentViewController)
view.addSubview(attachmentViewController.view)
attachmentViewController.view.snp.makeConstraints { make in
make.left.equalTo(view)
make.right.equalTo(view)
make.top.equalTo(view)
make.bottom.equalTo(view)
}
attachmentViewController.didMove(toParentViewController: window.rootViewController)
However, this doesn't call the viewDidAppear or viewWillDisappear methods... Why is that? I really need it to.
Instead of doing all that, simply present the view controller (don't push it as suggested).
let destination = SomeViewController.instantiateFromStoryboard(self.storyboard!)
present(destination, animated: true, completion: nil)
Focusing on the "why is that?" of your question.
When you call addChildViewController to a view you're not changing the "stack" of view controllers at all or the state of the host view controller; you're just adding a view controller as a child controller of the main view.
Usually when you work with child view controllers you orchestrate calls like willMove and didMove to trigger the view controller lifecycle behaviour.
In your case, you may be better off with a push or present. Present will give you the capability of overlaying a view controller.
As a note, I have used an approach similar to what you describe for managing sign in/out states adding either a signed in child view controller or a signed out view controller. In which case, when they change I usually call methods like:
// To add the child
addChildViewController(child)
view.addSubview(child.view)
child.didMove(toParentViewController: self)
// To remove the child.
child.willMove(toParentViewController: nil)
child.removeFromParentViewController()
child.view.removeFromSuperview()

How to hide child view from parent view after some delay

hide child view after few seconds
I set time for that but i cant access child viewcontroller in my timer function
I tried dissmiss , removefromparent about not worked.
only self.view.isHidden = true is worked
I can't place it in timer
My Parent view
Child View:
Button code:
Timer code:
In Like_btn_Action() function, you:
create an instance of LikeViewController
add it as a child view controller
add its view to your view
set that view's background color
and then the function exits. At this point, you no longer have a reference to your instance of LikeViewController ... likeVC has gone out of scope.
You need to use a class-level var to maintain the reference to the loaded child view controller, along these lines:
var likeVC: LikeViewController?
#IBAction func Like_btn_Action(_ sender: Any) {
likeVC = self.storyboard?.instantiateViewController( etc ...)
}
Then, when you want to remove the view you added, you can "get to it" via:
likeVC.view.removeFromSuperview()
for example.

addChildViewController method is only for adding child viewControllers to containerViewController?

I see the description of this method in Apple says
func addChildViewController(_ childController: UIViewController)
This method is only intended to be called by an implementation of a custom container view controller. If you override this method, you must call super in your implementation.
I see, so many examples that people use addChildViewController everywhere without containerViewController.
For example: I did not use containerView. I added like in the below? İt is correct?
// Create child VC
let childVC = UIViewController()
// Set child VC
self.addChildViewController(childVC)
// Add child VC's view to parent
self.view.addSubview(childVC.view)
// Register child VC
childVC.didMove(toParentViewController: self)
// Setup constraints for layout
childVC.view.translatesAutoresizingMaskIntoConstraints = false
childVC.view.topAnchor.constraint(equalTo: heroView.bottomAnchor).isActive = true
childVC.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
childVC.view.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
childVC.view.heightAnchor.constraint(equalToConstant: height).isActive = true
Like the documentation says, that method is intended to be used by view controllers that can contain another view controller. An example would be the navigation and tab bar controllers.
If you implemented a custom controller that, for example, put one controller on the top half on the screen and one on the bottom half, when you set the bottomHalfViewController property, you would call the addChildViewController method to let your controller know that it should handle that view controller as it's child.
This means that it will forward all view lifecycle calls like viewWillAppear:

Container views with segmented control in swift

I have a segmented control with three segments. "Cattle", "Sheep" and "Goats". In Sheep and Goats there is another segmented control "RFID" and "Mobs"
I have used three container views on a parent viewController, a cattleView, sheepGoatMob view and a sheepGoatRFID view which have UITableViewControllers CattleTableViewController, SheepGoatMobTableViewController and SheepGoatRfidTableViewController. The parent view contains the if statement to hide/show each view, which works okay..
The problem that I am having is that each child view needs to be able to send the info on their pages to a soap web service from a UIBarButtonItem on the parent view. My first thought was to have a "send" button in each child view but because all three views are loaded into memory when the app starts, the button doesn't know which view function to call.
EDIT : How can I accomplish setting a button in each of the three views for the UIBarButtonItem of the parent viewController and allowing the correct function from the childViewControllers to be called?
Option 2: How could I access the three childviewcontroller's function through a UIBarButtonItem on the parent viewcontroller?
I found a solution to have all three views loaded into memory and be able to change which function I am calling using #Julian's response: Objective-c: How to invoke method in container view controller
//Determine which view is showing and point to the correct child class
func sendTransactionButton(sender: UIBarButtonItem) {
log.debug("send transaction button called p2p")
for childViewController in self.childViewControllers {
if childViewController.isKindOfClass(CattleTableViewController) && containerTableViewCattle.hidden == false {
var cattleVC = childViewController as! CattleTableViewController
cattleVC.transactions()
} else if childViewController.isKindOfClass(SheepGoatRfidTableViewController) && containerSheepGoatsRfid.hidden == false {
var sheepGoatRFIDVC = childViewController as! SheepGoatRfidTableViewController
sheepGoatRFIDVC.transactions()
} else if childViewController.isKindOfClass(SheepGoatTableViewController) && containerTableViewSheepGoats.hidden == false {
var sheepGoatsMob = childViewController as! SheepGoatTableViewController
sheepGoatsMob.transactions()
}
}
}
You need to ensure that your other views are hidden or you will get a warning from xcode.

Resources