Custom segue to sibling view controller - ios

I have 3 pages that should segue like so...
,-(1)-> Home <-(2)-,
v v
Login ----(3)---> Register
where Login -> Register segue is triggered by a "Don't have an account? Register now." button, you know, something like that... Also, mind the unidirectional arrow.
All segues are already implemented, except for one: when a segue with this order is triggered:
Home -> Login -> Register -> Home
where Register -> Home is triggered via back button.
Basically, I need to know how to set Register's parentViewController to Home so that when the Back button is pressed (which then calls performSegueWithIdentifier with my custom unwind segue), Register would then unwind to Home.
Based on the segue order chain mentioned above, Register unwinds to a dismissed Login, I believe.
P.S. I'm using the interface builder for the views.
P.S. Login and Register are presented MODALLY, so they go on top of Home

To add custom animation to present view controller using custom animation
You have call self. performAnimation() function on your back button of Registration and Login. The below code is for Registration and Home screen.
// This function will be present in your Registration viewController
func performAnimation() {
//Your storyboard name
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let YourNavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("YourNavigationController") as! UINavigationController
let mainVC = mainStoryboard.instantiateViewControllerWithIdentifier("YourHomeScreenIdentifier") as! YourHomeScreen
initialNavigationController.viewControllers = [mainVC]
self.presentViewController(YourNavigationController, animated: false, completion: nil)
(mainVC as YourHomeScreen).fromRegisterSelector()
}
//These function or line of code should be present in your Home viewController
func fromRegisterSelector()
{
hasComeHereFromRegVC = true
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if hasComeHereFromRegVC
{
addSignInViewAndAnimateIt()
}
}
func addSignInViewAndAnimateIt()
{
hasComeHereFromRegVC = false
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let mainNavigationController = mainStoryBoard.instantiateViewControllerWithIdentifier("YourNavigationController") as! UINavigationController
let RegVC = mainStoryBoard.instantiateViewControllerWithIdentifier("RegViewController") as! YourRegViewController
mainNavigationController.viewControllers = [RegVC]
self.view.addSubview(mainNavigationController.view)
self.view.bringSubviewToFront(mainNavigationController.view)
UIView.animateWithDuration(0.3, animations: {
// To change the screen sliding direction change the origin.x to origin.y and frame.width to frame.height in the line below
mainNavigationController.view.frame.origin.x += self.view.frame.width
}) { (finished) -> Void in
mainNavigationController.view.removeFromSuperview()
}
}
Hope this will help you.

Related

How to check whether a specific UiViewcontroller(Tabbar Embedded) is in the navigationController rack?

I have a SignInVc as a starting point and a skip button. If user taps skip, e goes to home page and when he taps any button he is pushed to SignInVc.
The homeVC has TabBar, like its one of the 4 tab bar Vc's.
if let viewControllers = self.navigationController?.viewControllers {
for controller in viewControllers
{
if controller == (tabBarController?.viewControllers![0]){
print("FOUND IT")
}
print(controller)
}
}
While debugging with breakpoints, i can see the home page in navigationController?.viewControllers
But i cannot access it!!, the print is not executed. What should i use in the RHS of == ?
The plan is to push to the homeVC instead of print code.
EDIT:
I'm adding the screen shots of the debug below
Here i want to get to the view controller at Index 2
[
I do not think that you have such hierarchy as you've described.
Really you have
NavigationController -> TabBarController -> HomeViewController or
TabBarController -> NavigationController -> HomeViewController
Properties .navigationController and .tabBarController find nearest accessible Navigation and TabBar controller.
Just exam your hierarchy in storyboard or in code, and you will fix your problem.
UPD.
Based on your screen, you should find tabBar controller first, and find HomeViewController in tabBarController. I think, the code should looks like:
if let tabBar = navController.viewControllers.first(where: { $0 is UITabBarController} ){
let homeController = tabController.viewControllers?.first(where: { $0 is HomeViewController})
print("Home controller: \(home)")
}
I am not sure whether am right,
logically declare a global variable,
var initiateHomePage: Bool? // declare above or outside any swift file
For button actions
case 1
#IBAction func skipButtonTapped(_ sender: Any) {
initiateHomePage = true // should go homepage
}
case 2
#IBAction func anyButtonTapped(_ sender: Any) {
initiateHomePage = false // should go SignInVC
}
Atlast
while executing
if initiateHomePage == true {
// redirect to home page
// use this to redirect to tab bar
if let viewControllers = self.navigationController?.viewControllers {
for controller in viewControllers
{
if controller == (tabBarController?.viewControllers![0]){
print("FOUND IT")
}
print(controller)
}
}
// or use this
let ViewController:UIStoryboard = UIStoryboard(name: "Module", bundle: nil)
let tabBarController = ViewController.instantiateViewController(withIdentifier: "tabBar") as! UITabBarController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = tabBarController
} else {
// redirect to SignINVC
}

how to block presses around child view controller using swift 4.0?

i'm attaching a child view controller to my view :
func showRaitingDialog () {
let popupRateExpiriance = UIStoryboard (name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ratePopupId") as! RateViewController
//adding the popup view to the corrent view controller
print ("this happens after")
self.addChildViewController(popupRateExpiriance)
popupRateExpiriance.refrenceToController = self
popupRateExpiriance.view.frame = self.view.frame
self.view.addSubview(popupRateExpiriance.view)
popupRateExpiriance.didMove(toParentViewController: self)
}
that child view controller is actually just a costume dialog that i did in my app.
my question is how do i block the presses around this dialog ? (so far the user can press on the screen blow it if he presses around the view controller itself)
You need to build a custom component and introduce the padding between the newly build child and your current one.
#IBAction func buttonAction(_ sender: Any) {
showRaitingDialog ()
}
func showRaitingDialog () {
let popupRateExpiriance = UIStoryboard (name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ratePopupId") as! RateViewController
//adding the popup view to the corrent view controller
addChild(popupRateExpiriance)
// popupRateExpiriance.refrenceToController = self // << maybe you should create an interface / delegate
popupRateExpiriance.view.frame = self.view.frame
view.addSubview(popupRateExpiriance.view)
popupRateExpiriance.didMove(toParent: self)
}
The controller on the right has the background view colour set to clear.
Here is the result at runtime after the button has been pressed to display the child controller (the user can no longer press the button).

Presenting custom popup from popup then dismissing first popup causes flicker

Currently I create a custom popup A then when a button in it is pressed dismiss it and in the completion handler create a new popup B.
Both popups are similar in that they use a black view with alpha set to a value to simulate the grayed out screen affect that a standard alert provides.
However dismissing A before creating B causes a flicker. I would like to create B before dismissing A but haven't found a good way to do this.
Ideas on how to do this and avoid the flicker?
I'm thinking of putting the black view with the alpha set in the view controller screen that shows popup A and turning it on when popup A is shown and off when popup B is dismissed. This doesn't seem like the best solution however. Another way would be to have a single popup and show hide controls but this seems not a good solution either because it makes the storyboard VC messy.
Here's how the code looks now:
From a menu the popup A is created:
let storyBoard = UIStoryboard(name: "MenuStoryboard", bundle: nil)
let aPopup = storyBoard.instantiateViewController(withIdentifier: "Popup_A")
present(aPopup, animated: false, completion: nil)
Then from button action of Popup A:
self.dismiss(animated: false) {
let storyBoard = UIStoryboard(name: "MenuStoryboard", bundle: nil)
let bPopup = storyBoard.instantiateViewController(withIdentifier: "PopUp_B")
if let topViewController = UIApplication.shared.topMostViewController {
topViewController.present(bPopup, animated: false, completion: nil)
}
}
And the extensions:
extension UIViewController {
var topMostViewController : UIViewController {
if let presented = self.presentedViewController {
return presented.topMostViewController
}
if let navigation = self as? UINavigationController {
return navigation.visibleViewController?.topMostViewController ?? navigation
}
if let tab = self as? UITabBarController {
return tab.selectedViewController?.topMostViewController ?? tab
}
return self
}
}
extension UIApplication {
var topMostViewController : UIViewController? {
return self.keyWindow?.rootViewController?.topMostViewController
}
}
The way you do is not recommended, a View Controller should not be concerned of "dismissing itself" and then "asking" another view controller to present a new view controller.
I'd use delegation from PopupA to communicate back to whatever object presented it. That object SHOULD dismiss the PopupA view controller.
Once completed, you could try to display PopupB.

Segue from popup ViewController Swift

I have app with 7 screens(VC) which are embedded in navigation controller.
And I have one separate VC that is not embedded. This VC is acting like custom popup class PopupView: UIViewController {} and get's called by pressing button from every screen that I have in my app using custom segue (setup as custom segue in storyboard):
open class MIBlurPopupSegue: UIStoryboardSegue {
open override func perform() {
MIBlurPopup.show(destination, on: source)
} }
In this popup there's a button that should open another VC (VC always the same) that is embedded in navigation stack.
What I'm trying to achieve is to actually open that VC that is inside navigation stack by pressing button in Popup VC and then get back to the screen where Popup was called.
So, user journey will look like - Opened VC1(2,3,5,6,7) -> Called popup VC -> Pressed button -> opened VC4 -> pressed navigation back button -> returned to VC1.
I what I have right now:
Connected in storyboard all 6 screens to VC4, with segues ids
Tried performSegue(withIdentifier: "toVC4"), present(vc, animated: true, completion: nil)
let storyboard = UIStoryboard(name: "MyStoryboardName", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "VC4")
self.present(controller, animated: true, completion: nil)
Using protocols to call func in VC1 but failed.
I'm definitely missing something and would be very thankful if someone could provide code sample to solve this issue.
You can try this inside the popup button's action
self.dismiss(animated:true) {
if let nav = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
let vc1 = storyboard!.instantiateViewController(withIdentifier: "MenuId")
let finalVC = storyboard!.instantiateViewController(withIdentifier: "finalId")
nav.setViewControllers([vc1,vc4],animated:true) // set it to false if you want
}
}

How to push viewcontroller correctly

This is my storyboard:
Short Description:
My App starts with the LaunchController
a modal segue shows the Reveal View Controller
this bring the Menu Controller and my Main Navigation Controller (ID
"NavController"; green Navbar) together. this will create a slide
menu. (Basic Code:
appcoda.com/ios-programming-sidebar-navigation-menu/)
my Main Navigation Controller shows a TableViewController.
this one have a menu button (3 Lines) which make the slide menu
visible
the plus icon willo push the last view Controller (ID: "VC1").
My Problem:
I would like to set quick actions for my app.
This code help works for that:
#available(iOS 9.0, *)
func handleShortcut( shortcutItem:UIApplicationShortcutItem ) -> Bool {
var succeeded = false
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("NavController")
self.window?.rootViewController = initialViewController
let navVC = self.window?.rootViewController as! UINavigationController
switch shortcutItem.type {
default:
navVC.pushViewController(storyboard.instantiateViewControllerWithIdentifier("VC1"), animated: false)
succeeded = true
break
}
return succeeded
}
This Code set the NavController as initial Controller und push the to VC1.
This works fine.
With the X icon in VC 1, i use the unwind function back to TableView.
The Problem: if i use the undwind function and fall back to tableview i can't open the slide menu. A Touch on the menu icon give no reaction.
The Problem can be, that i start the app with the quick action behind the Reveal View Controller.
How can I solve this problem?
Did you try to make the reveal view controller the entry point of your app and deleting the launch controller, because if you just want to go back to the main view you could just do this :
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateInitialViewController() as UIViewController!
self.presentViewController(controller, animated: false, completion: nil)
If you cannot could you explain the purpose of the launch controller?

Resources