How to hide child view from parent view after some delay - ios

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.

Related

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()

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:

Is it fine to nest a UIViewController within another without using addChildViewController?

I'm trying to make a custom ContainerViewController, but due to lots of difficulties with the ViewController transitions and making everything interactive, I've decided to mimic that functionality myself.
What I basically want to do, is have a paginated UIScrollView (the HeaderView) on the top control different another UIScrollView (the ControllersView) below that contains ViewControllers as pages so that as you swipe to a new page on the HeaderView, it also swipes to the next viewcontroller on the ControllersView. This is what the setup would look like.
My question is, is there anything wrong with having the aforementioned setup? All I'll do to add the view controllers to the ControllersView is just something like: controllersView.addSubview(pagecontroller1.view).
Some posts online seem to say that "the appropriate ViewController functions won't be called" or whatever. What do I seem to be missing here? I'm guessing there's a lot of dismissing and admitting of ViewControllers that I need to call every time a ViewController is out of frame right?
To clarify the question: Is it ok/efficient to do this? Should I be calling some viewWillAppear/disapper functions when the VC's get in and out of frame? If so, what should I call? I'm realizing that if I were to set things up this way, I need to manage a lot of things that are usually handled automatically, but as I mentioned before, custom ContainerViewControllers have failed me and I'm going with this.
PS. If you seem to still be lost on how this will look like, see my previous question here where I originally wanted to use a Container ViewController. There's a much better mockup there.
You can add and remove VC In Container Views
For - Is it ok/efficient to do this? Should I be calling some viewWillAppear/disapper functions when the VC's get in and out of frame? If so, what should I call?
As, We need to call WillAppear and Disappear Func when Adding and removing a VC , Thus Try using below Functions That will Handle these Responses
I use the Two specific Functions to add and remove Controller in ContainerView/UIView/SubView in ScrollView inside a UIView
To Add
private func add(asChildViewController viewController: UIViewController)
{
// Configure Child View
viewController.view.frame = CGRect(x: 0, y: 0, width: self.firstContainer.frame.size.width, height: self.firstContainer.frame.size.height)
// Add Child View Controller
addChildViewController(viewController)
viewController.view.translatesAutoresizingMaskIntoConstraints = true
// Add Child View as Subview
firstContainer.addSubview(viewController.view)
// Notify Child View Controller
viewController.didMove(toParentViewController: self)
}
To Remove
private func remove(asChildViewController viewController: UIViewController)
{
// Notify Child View Controller
viewController.willMove(toParentViewController: nil)
secondContainer.willRemoveSubview(viewController.view)
// Remove Child View From Superview
viewController.view.removeFromSuperview()
// Notify Child View Controller
viewController.removeFromParentViewController()
}
Creating Object
private lazy var FirstObject: firstVC =
{
// Instantiate View Controller
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "firstVC") as! firstVC
// Add View Controller as Child View Controller
self.addChildViewController(viewController)
return viewController
}()
For - controllersView.addSubview(pagecontroller1.view)
Answer - Yes Approbate func wont be called if pagecontroller1 is not loaded in to memory stack, to load that you need to notify pagecontroller1 that it is going to be added to memory stack as Child View , Just as We initiate a Controller and basically notifies the Controller to get its component loaded to memory stack to get some memory allocations
For Question - Is it fine to nest a UIViewController within another without using addChildViewController?
Check apple Documentation - https://developer.apple.com/documentation/uikit/uiviewcontroller/1621394-addchildviewcontroller
This is necessary just as to notify the controller who is going to be added in Another Parent View as Child
Sample Project
https://github.com/RockinGarg/Container_Views.git
Or
https://github.com/RockinGarg/ContainerView-TabBar.git
If Question is Still not answered Please Tell me what Func Exactly you want to handle by yourself

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.

Swift: Perform a function on ViewController after dismissing modal

A user is in a view controller which calls a modal. When self.dismissViewController is called on the modal, a function needs to be run on the initial view controller. This function also requires a variable passed from the modal.
This modal can be displayed from a number of view controllers, so the function cannot be directly called in a viewDidDisappear on the modal view.
How can this be accomplished in swift?
How about delegate?
Or you can make a ViewController like this:
typealias Action = (x: AnyObject) -> () // replace AnyObject to what you need
class ViewController: UIViewController {
func modalAction() -> Action {
return { [unowned self] x in
// the x is what you want to passed by the modal viewcontroller
// now you got it
}
}
}
And in modal:
class ModalViewController: UIViewController {
var callbackAction: Action?
override func viewDidDisappear(_ animated: Bool) {
let x = … // the x is what you pass to ViewController
callbackAction?(x)
}
}
Of course, when you show ModalViewController need to set callbackAction like this modal.callbackAction = modalAction() in ViewController
The answer supplied and chosen by the question asker (Michael Voccola) didn't work for me, so I wanted to supply another answer option. His answer didn't work for me because viewDidAppear does not appear to run when I dismiss the modal view.
I have a table and a modal VC that appears and takes some table input. I had no trouble sending the initial VC the modal's new variable info. However, I was having trouble getting the table to automatically run a tableView.reloadData function upon dismissing the modal view.
The answer that worked for me was in the comments above:
You likely want to do this using an unwind segue on the modal, that
way you can set up a function on the parent that gets called when it
unwinds. stackoverflow.com/questions/12561735/… – porglezomp Dec 15
'14 at 3:41
And if you're only unwinding one step (VC2 to VC1), you only need a snippet of the given answer:
Step 1: Insert method in VC1 code
When you perform an unwind segue, you need to specify an action, which
is an action method of the view controller you want to unwind to:
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
//Insert function to be run upon dismiss of VC2
}
Step 2: In storyboard, in the presented VC2, drag from the button to the exit icon and select "unwindToThisViewController"
After the action method has been added, you can define the unwind
segue in the storyboard by control-dragging to the Exit icon.
And that's it. Those two steps worked for me. Now when my modal view is dismissed, my table updates. Just figured I'd add this, in case anyone else's issue wasn't solved by the chosen answer.
I was able to achieve the desired result by setting a Global Variable as a boolean value from the modal view controller. The variable is initiated and made available from a struct in a separate class.
When the modal is dismissed, the viewDidAppear method on the initial view controller responds accordingly to the value of the global variable and, if needed, flips the value on the global variable.
I am not sure if this is the most efficient way from a performance perspective, but it works perfectly in my scenario.

Resources