I am trying to use same View Controller for showing my second view which should be inside Second View Controller. The motive is to reuse the same View Controller for different View while not losing the push animation effect.
See my code below:-
class PictureCaptureVC: UIViewController {
public var isReviewPhoto = false
override func viewDidLoad() {
super.viewDidLoad()
if isReviewPhoto {
btnSubmit.isHidden = false
} else{
btnSubmit.isHidden = true
}
}
#IBAction private func handleReviewBtn(_ sender: UIButton) {
if let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "PictureCaptureVC") as? PictureCaptureVC {
secondViewController.isReviewPhoto = true
self.present(secondViewController, animated: true, completion: nil)
self.dismiss(animated: false, completion: nil)
}
}
}
It is creating a UITransitionView Over the Top View and i am even concerned about memory leaks.
See This Image
Any Help would be highly appreciated!
Related
I have two Present view controllers. The thing i want to do is when the second Present view controller is dismissed it will automatically reload the first present view controller(Table view). note: first view controller holds a table view, basically i want to reload the table view of first controller.
ViewWillAppear code:
override func viewWillAppear(_ animated: Bool) {
tableViewReloadFromCreateProductVC()
}
func tableViewReloadFromCreateProductVC () {
tableView.reloadData()
}
Calling from second view controller code:
SecondViewController.tableViewReloadFromCreateProductVC()
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
FirstViewController calling 2nd view controller
#IBAction func CallSecondViewButton(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController
controller.modalPresentationStyle = .fullScreen
self.present(controller, animated: true, completion: nil)
}
just write the code in viewWillAppear() method of the view controller that you want to reload like this
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
//perform api call if any
yourTableView.reloadData()
}
2nd view controller
#IBAction func CloseButton(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
after dissmissing the viewWillAppear method of firstViewController will autometically called.
The First two snippets are for first view controller and the last one is for second view controller
Reloading the entire table view could sometimes be costly and it also sounds like you're making an API call as well so unless you want your table view to be reloaded and the API call made every time the view controller becomes visible whether or not you've made changes to it, you want the reloading to be done only when it's necessary.
You can try it in a few different ways:
class CreateProductVC: UITableViewController {
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.delegate = self
present(secondVC, animated: true, completion: nil)
}
}
}
class SecondViewController: UIViewController {
weak var delegate: CreateProductVC?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
self.delegate?.tableView.reloadData()
}
}
}
or
class CreateProductVC: UITableViewController {
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.isDismissed = { [weak self] in
self?.tableView.reloadData()
}
present(secondVC, animated: true, completion: nil)
}
}
}
class SecondViewController: UIViewController {
var isDismissed: (() -> Void)?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
self.isDismissed?()
}
}
}
or if you want more fine-grained control over what to do with the new data:
protocol ReloadVC {
func reload(_ value: String)
}
class CreateProductVC: UITableViewController, ReloadVC {
var dataSource: [String]! {
didSet {
tableView.reloadData()
}
}
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.delegate = self
present(secondVC, animated: true, completion: nil)
}
}
func reload(_ value: String) {
dataSource.append(value)
}
}
class SecondViewController: UIViewController {
var delegate: ReloadVC?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
let someValue = "Some Value"
self.delegate?.reload(someValue)
}
}
}
We have Router class to navigate the viewController to another view controller, It's working as expected but when randomly the viewControllersStack gets nil and crash occurred. We tried to use it "if let" to avoid the crash but the issue here is black screen appeared when the viewControllersStack is nil. so we have reverted it back. Can you suggest why the navigation stack is nil if the navigation is nil how to handle it?
private func PopOrPushToViewController(_ strControllerClass: String) {
//get the list of controllers in the stack
let viewControllersStack: [UIViewController] = self.navigationController!.viewControllers as [UIViewController]
var boolDidNaviagtion = false
for viewController in viewControllersStack {
if boolDidNaviagtion {
viewController.removeFromParent()
}
if String(describing: type(of: viewController)) == strControllerClass {
boolDidNaviagtion = true
self.navigationController?.popToViewController(viewController, animated: true)
}
}
if !boolDidNaviagtion {
let viewController = NavigationController.sharedInstance.storyboardViewControllerFromString(strControllerClass)!
self.navigationController!.pushViewController(viewController, animated: true)
}
}
class AddTripViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func navigate(_ sender: Any) {
popOrPushToViewController( "ListViewController")
}
}
The problem is likely your use of:
viewController.removeFromParent()
If you pop to a VC in the stack, the other VCs will be removed automatically.
Try changing your func to this:
private func PopOrPushToViewController(_ strControllerClass: String) {
// get the list of controllers in the stack
if let vcStack: [UIViewController] = self.navigationController?.viewControllers {
var didPop = false
for vc in vcStack {
// if we find the desired VC already in the navVC's stack of controllers,
// pop to it, set the didPop flag to true, and quit looking
if String(describing: type(of: vc)) == strControllerClass {
self.navigationController?.popToViewController(vc, animated: true)
didPop = true
break
}
}
// if we did NOT pop to the desired VC,
// instantiate it and push it onto the stack
if !didPop {
if let vc = NavigationController.sharedInstance.storyboardViewControllerFromString(strControllerClass) {
navigationController?.pushViewController(vc, animated: true)
}
}
}
}
I have two view controller that opens modally. When the first VC closed then the second should be opened. But when I close the first one, the second one is not displayed at all.
what is the problem?
My code is:
self.dismiss(animated: true) {
let flowVC = LanguageFlowViewController()
self.present(flowVC, animated: true)
}
You need reference of view controller from where you to present first view controller.
For example, you have view controller name as X, from there your first view controller A present. So you need reference of X to present B, because A will not be available in memory.
So when you try to present second view controller using self, it will do nothing.
So, for solution assign reference of X view controller to A. In class A, declare:
var refX: X?
While present A from X, set self to refX. Like:
var aVC = A() // This is temp, you need to instantiate your view controller here.
aVC.refX = self
self.present(aVC, animated: true, completion: nil)
Now, inside view controller A, when dismiss:
var bVC = B() // This is temp, you need to instantiate your view controller here.
self.dismiss(animated: true) {
if self.refX != nil {
self.refX?.present(bVC, animated: true, completion: nil)
}
}
I hope this will help you.
If you want to open modally ThirdViewController after Dismiss SecondViewController then you have to create protocol for it.
Like we have three UIViewController(FirstViewController,SecondViewController and
ThirdViewController)
Step 1: We need to create a protocol in SecondViewController as given below code.
protocol DismissedViewProtocal {
func dismissView()
}
class SecondViewController: UIViewController {
var delegate: DismissedViewProtocal?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func dismissSecondViewAction(_sender : AnyObject) {
dismiss(animated: true) {
self.delegate?.dismissView()
}
}
Step 2: You need to add protocol in FirstViewController as given below
class FirstViewController: UIViewController, DismissedViewProtocal {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func anAction(_sender : AnyObject){
let flowVC = self.storyboard?.instantiateViewController(withIdentifier:"SecondViewController") as? SecondViewController
secondVC?.delegate = self
self.present(secondVC!, animated: true) {
}
}
func dismissView() {
let thirdVC = self.storyboard?.instantiateViewController(withIdentifier:"ThirdViewController")
self.present(thirdVC!, animated: true) {
}
}
}
Your are dismissing the current view controller by calling self.dismiss().
Therefore it is impossible for it to present anything anymore, since it is removed from the view hierarchy. As others have mentioned, try using the self.presentingViewController or self.navigationController (if it is on a navigationController) to present your new view.
However, if you need maximum flexibility create a delegate protocol. Create a protocol with a function presentForChild(viewController: UIViewController). Before your previous view presents the view from which the code in your question belongs to, give it a reference of the protocol.
Example:
protocol ChildPresentDelegate: class {
func presentForChild(vc: UIViewController)
}
class FirstController: UIViewController, ChildPresentDelegate {
func presentForChild(vc: UIViewController) {
present(vc, animated: true, completion: nil)
}
/**
other code
*/
func showControllerAsWasShownInTheQuestion() {
let controller = SecondController()
controller.delegate = self
present(controller, animated: true, completion: nil)
}
}
class SecondController: UIViewController {
weak var delegate: ChildPresentDelegate?
func dismissMySelf() {
self.dismiss(animated: true) {
delegate?.presentForChild(vc: LanguageFlowViewController())
}
}
}
I'm using the Hero library to do a transition between view controllers.
First view controller:
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var people = [Person]()
override func viewDidLoad() {
super.viewDidLoad()
hero.isEnabled = true
hero.modalAnimationType = .push(direction: .right)
}
#IBAction func handleButton(){
let view = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! UIViewController
present(view, animated: true, completion: nil)
}
}
Second view controller:
class Second: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
hero.isEnabled = true
// Do any additional setup after loading the view.
}
#IBAction func handleBackButton(){
hero.modalAnimationType = .push(direction: .left)
hero.dismissViewController()
}
}
It presents the new view without any animation. When I dismiss the second controller, it will apply the correct animation. How do I present the second view with an animation?
Okay found the solution.
In the first case where I have:
#IBAction func handleButton() {
let view = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! UIViewController
present(view, animated: true, completion: nil)
}
I have to set the animation there on the view.
#IBAction func handleButton() {
let view = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! UIViewController
view.hero.modalAnimationType = .push(direction: .right)
present(view, animated: true, completion: nil)
}
works
Set the modal animation type by setting the Hero extension heroModalAnimationType:
hero.heroModalAnimationType = .push(direction: .right)
Don't forget to disable the default animation for the transition using the Hero.shared object's methods :
func disableDefaultAnimationForNextTransition()
func setDefaultAnimationForNextTransition(_ animation: HeroDefaultAnimationType)
I want to add a transition effect to my app from a ViewController to another.
I want use the transition effect that the Navigation Controller usually add (sliding effect) but without using the Navigation Controller.
What is the simplest and easiest way to achieve that? (I'm using swift 3)
EDIT:
My Code Now:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func GoToMenu(_ sender: UIButton) {
//TRANSITION EFFECT
let nextVCID="010101"
guard let presentedController = self.storyboard?.instantiateViewController(withIdentifier: nextVCID) else { return }
presentedController.modalTransitionStyle = UIModalTransitionStyle.coverVertical
self.present(presentedController, animated: true, completion: nil)
}
}
You can present it modaly and set modal transition style you like.
guard let presentedController = self.storyboard?.instantiateViewController(withIdentifier: nextVCID) else { return }
presentedController.modalTransitionStyle = UIModalTransitionStyle.coverVertical
self.present(presentedController, animated: true, completion: nil)