change a view programmatically with swift-slide-menu - ios

I am using this library: swift-slide-menu
Is there any way to change a view programmatically? I am using the same viewcontroller to show two different datasets in a tableview. I have two buttons in the menu, one for each dataset. When clicking on button1 I go to the ListVC and everything works fine. When clicking on button2 I go to an empty ViewController that sets the url for the dataset and segues right away to ListVC.
When I do the segue, the menu button is not shown in ListVC. This is probably because I am not adding a childView to the BaseViewController when I segue. But is there any way to add a code inside my empty ViewController that adds ListVC as a childView, instead of doing a normal segue?
PS.
I am trying to prevent having the same code inside two different viewcontrollers and having 2 copies of the same vc in storyboard.
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
addChildView("AllDatasetID", titleOfChildren: "All data", iconName: "icon1") //ListVC
addChildView("FilteredDatasetID", titleOfChildren: "My data", iconName: "icon2") //EmptyVC that segues to ListVC
}
}
class EmptyVC: UIViewController {
override func viewDidAppear(_ animated: Bool) {
self.performSegue(withIdentifier: "toListVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toListVC" {
if let destinationVC = segue.destination as? ListVC {
destinationVC.theUrl = Settings.myFilterUrl
}
}
}
}

The solution was to access inside the ListVC a variable from the menu that stored the title for the current view. The menu subclasses BaseViewController and several variables are accessable from the BaseViewController through the navigationController.
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
addChildView("ListVCScreenID", titleOfChildren: "My datapoints", iconName: "icon1")
addChildView("ListVCScreenID", titleOfChildren: "All datapoints", iconName: "icon2")
}
}
class ListVC: UIViewController {
var theUrl: String?
override func viewDidLoad() {
super.viewDidLoad()
let vc = self.navigationController?.viewControllers
var counter = 0
for v in vc! {
if v as? ViewController != nil {
print("title is: \(v.title)")
if(v.title == "My datapoints") {
theUrl = "getMyData"
}
else {
theUrl = "getAllData"
}
}
}
}
}

Related

How to pass which function should call in next screen after tap on button based on flow without using enum in IOS Swift?

I am using MVVM Arch with RxSwift, I have one screen commonly used for more than 8 flows, Here I don't want to use enum and switch casses but I have to call different functions based on flow and route to different screens
Ex: I have Two classes A and B and both will go to C, Here C have one button with two functions Now once we navigate to C and I click button in C then it should call function related to A class and route to some other controller
How can I do this without enums
Mean I have to decide in A or B classes which function should call in C after clicking on button
class ViewControllerA: UIViewController {
override func viewDidLoad() {
}
#IBAction func btn_clicked(_ sender: Any) {
let vc: ViewControllerC =
self.storyboard?.instantiateViewController(withIdentifier:
"ViewControllerC") as! ViewControllerC
vc.isFrom = "A"
self.navigationController?.pushViewController(vc, animated: true)
}
}
class ViewControllerB: UIViewController {
override func viewDidLoad() {
}
#IBAction func btn_clicked(_ sender: Any) {
let vc: ViewControllerC =
self.storyboard?.instantiateViewController(withIdentifier:
"ViewControllerC") as! ViewControllerC
vc.isFrom = "B"
self.navigationController?.pushViewController(vc, animated: true)
}
}
class ViewControllerC: UIViewController {
var isFrom = ""
override func viewDidLoad() {
super.viewDidLoad()
if isFrom == "A"{
self.callForA()
}else if isFrom == "B"{
self.callForB()
}
}
func callForA(){
//Your Code
}
func callForB(){
//Your Code
}
}

Delegate between TableViewController and ViewController

I'm in my first week of developing in iOS and have become stuck on an issue with passing data between view controllers. My set up consists of a view with VC having a button in it and also a container view (no associated view controller). The container view has an embedded Segue to a TableView with TableViewController. The table has 6 rows and each row has a stepper that can change the value of a text view on the associated row. What I would like to do is collect the values of all the textviews when I press the button on the main view.
I am trying to use delegate to do this but when I press the button the returned value is always nil. I believe the problem is to do with the fact the VC is not being passed to the table view controller via the prepareForSegue function but I'm not sure why? Could be to do with the load order of the controllers?
import UIKit
class PredictionViewController: UIViewController, PredictionDelegate {
var predictionData: String!
#IBOutlet weak var messageTextBox: UITextView!
#IBOutlet weak var predictionSubmitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.messageTextBox.isEditable = false
}
override func viewDidAppear(_ animated: Bool) {
}
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "predictionSegue") {
// pass data to next view
let vc = segue.destination as! PredictionsTableViewController
vc.predictionHomeDelegate = self
}
}
func receiveData(with data: String) {
predictionData = data
print(predictionData)
}
#IBAction func predictionSubmitButtonAction(_ sender: UIButton) {
print(predictionData)
}
}
TableViewController: (stripped to minimum)
import UIKit
protocol PredictionDelegate: class {
func receiveData(with data: String)
}
class PredictionsTableViewController: UITableViewController, PredictionDelegate {
weak var predictionHomeDelegate: PredictionDelegate?
#IBOutlet weak var homeTeamScore1: UITextView!
#IBOutlet weak var homeTeamStepper1: UIStepper!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
}
func getPredictionList() {
//does some stuff
self.passDataBackwards()
}
func receiveData(with data: String) {}
func passDataBackwards() {
let data = "{\"score\":\"1\"}"
predictionHomeDelegate?.receiveData(with: data)
}
#IBAction func homeTeamStepper1Action(_ sender: UIStepper) {
let score = Int(sender.value).description
homeTeamScore1.text = score
self.passDataBackwards()
}
}
Any help gratefully received!
Edit:
After comments...
You have the wrong idea about Protocols and Delegates. They are not needed here.
Instead, in your "home" VC, get a reference to the embedded VC. Then, add a function in your embedded VC that you can call to get its data.
// "home" view controller
class PredictionViewController: UIViewController {
// this will be a reference to the embedded view controller
var embeddedVC: PredictionsTableViewController?
#IBAction func getDataButtonTapped(_ sender: Any) {
if let tableData = embeddedVC?.getMyData() {
print("Result: \(tableData)")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "predictionSegue") {
if let vc = segue.destination as? PredictionsTableViewController {
// get a reference to the embedded VC
self.embeddedVC = vc
}
}
}
}
// embedded view controller
class PredictionsTableViewController: UIViewController {
var numTaps = 0
func getMyData() -> String {
return "\(numTaps)"
}
#IBAction func didTap(_ sender: Any) {
numTaps += 1
}
}
You're close, but a couple mistakes...
Here is a very, very simple example. View controller with container, which has a view controller with a button.
Code:
import UIKit
// your protocol
protocol PredictionDelegate: class {
func receiveData(with data: String)
}
// embedded view controller
// NOTE: this should NOT include PredictionDelegate
class PredictionsTableViewController: UIViewController {
weak var predictionHomeDelegate: PredictionDelegate?
#IBAction func didTap(_ sender: Any) {
// on button tap, "send data back"
predictionHomeDelegate?.receiveData(with: "Test")
}
}
// "home" view controller
// NOTE: this DOES include PredictionDelegate
class PredictionViewController: UIViewController, PredictionDelegate {
func receiveData(with data: String) {
print(data)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "predictionSegue") {
if let vc = segue.destination as? PredictionsTableViewController {
// set self as the delegate of the embedded PredictionsTableViewController
vc.predictionHomeDelegate = self
}
}
}
}
Notes:
Do NOT include func receiveData(with data: String) {} in your embedded view controller
Do NOT assign PredictionDelegate to your embedded view controller
You need to hook your segue to the vc itself instead of the cell and use
self.performSegue(withIdentifier: "predictionSegue", sender: nil)
Since these are two separate screens I am not too sure it makes too much sense to have the button on the first view controller that submits data from the second, can the button not just be on the second. If for whatever reason it can't you could pass the data back to the first view controller on segueing back by adding a public variable to the first view controller and adding another prepare method to the second to pass the data back like you have done when adding the delegate.

how to send data from popover view controller to main view controller. Pass a string so that i can make that as the label text in the main view

I tried many methods to send data from my popup view controller to main view controller. but failed. can anybody help me with this.
i am using a "present as popover" segue. i want to the text entered in textfield of popover view as the label text of main view.
From Popup View, Data send to Main ViewController using protocol in Swift 3.
enter image description here
Complete Details are given below...
1. View Controller Implementing with Protocol named sendDataToViewProtocol.
import UIKit
class ViewController: UIViewController,sendDataToViewProtocol {
#IBOutlet weak var lshowDataLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnShowPopUpDialog(_ sender: Any) {
let popUpVc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PopupVIewController") as! PopupVIewController
//Don't forget initialize protocal deletage
popUpVc.delegate = self
self.addChildViewController(popUpVc)
popUpVc.view.frame = self.view.frame
self.view.addSubview(popUpVc.view)
popUpVc.didMove(toParentViewController: self)
}
func inputData(data: String) {
lshowDataLabel.text = data
}
}
Popup View Controller With Protocol named sendDataToViewProtocol below.
3.protocol declare outside the PopupVIewController.
Don't forget to assign ViewController to PopupVIewController .
In viewController withIdentifier: "PopupVIewController" , "PopupVIewController" is PopupVIewController storyborad Id.
Please see the attached image.
import UIKit
protocol sendDataToViewProtocol {
func inputData(data:String)
}
class PopupVIewController: UIViewController {
//Protocol object
var delegate:sendDataToViewProtocol? = nil
#IBOutlet weak var txtInputFieldText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor
.black.withAlphaComponent(0.8)
}
#IBAction func btnSendDataToViewController(_ sender: Any) {
//"Check Delegate nil"
if(delegate != nil){
//Check textField is empty
if(txtInputFieldText.text != ""){
//set textField Data to protocol Function
delegate?.inputData(data: txtInputFieldText.text!)
self.view.removeFromSuperview()
}
}
}
#IBAction func btnClose(_ sender: Any) {
self.view.removeFromSuperview()
}
}
First of all, keep a temporary variable in your Main ViewController. Let's call it:
var somethingCool: String?
Then, in your popup ViewController code, assuming you have your segue trigger there, you will need to add in a new method.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "your_segue_identifier" {
if let vc = segue.destination as? MainViewController {
vc.somethingCool = "whatever_you_want"
}
}
}

Pass data backward from detailViewController to masterViewController

I am trying to pass data back from the second viewController.
I can do that without NavigationController. But now I need to use NavigationController. Then my code does work as before. The data wont pass.
Here is the simple code:
In first viewController
class ViewController: UIViewController, backfromSecond {
#IBOutlet weak var text: UILabel!
var string : String?
override func viewDidLoad() {
super.viewDidLoad()
self.string = "Start here"
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.text.text = self.string
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationViewController = segue.destination as? secondViewController{
destinationViewController.delegate = self
}
}
func back(text: String) {
self.string = text
print(text)
}
}
And Second viewController:
protocol backfromSecond {
func back(text: String)
}
class secondViewController: UIViewController {
var string : String = "nothing here"
var delegate : backfromSecond?
override func viewDidLoad() {
super.viewDidLoad()
delegate?.back(text: string)
// Do any additional setup after loading the view.
}
}
What is wrong here?
Suppose A & B are two controllers and you first navigated from A to B with some data. And now you want to POP from B to A with some data.
Unwind Segues is the best and recommended way to do this.
Here are the steps.
Open A.m
define following method
#IBAction func unwindSegueFromBtoA(segue: UIStoryNoardSegue) {
}
open storyboard
Select B ViewController and click on ViewController outlet. press control key and drag to 'Exit' outlet and leave mouse here. In below image, selected icon is ViewController outlet and the last one with Exit sign is Exit Outlet.
You will see 'unwindSegueFromBtoA' method in a popup . Select this method .
Now you will see a segue in your view controler hierarchy in left side. You will see your created segue near StoryBoard Entry Piont in following Image.
Select this and set an identifier to it. (suggest to set the same name as method - unwindSegueFromBtoA)
Open B.m . Now, wherever you want to pop to A. use
self.performSegueWithIdentifier("unwindSegueFromBtoA", sender: dataToSend)
Now when you will pop to 'A', 'unwindSegueFromBtoA' method will be called. In unwindSegueFromBtoA of 'A' you can access any object of 'B'.
That's it..!
I think your problem is in the prepare for segue method. If the view controller is on a navigation stack i think your code should be something like
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationViewController = segue.destination as? UINavigationController).topViewController as! secondViewController{
destinationViewController.delegate = self
}
}
You can use unwind segues to pass data back.
Here's a tutorial
https://spin.atomicobject.com/2014/10/25/ios-unwind-segues/
This works me well.
1st VC
class ViewController: UIViewController, backfromSecond {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func Passingfrom1stVCTo2ndVC(_ sender: AnyObject) {
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "ViewController3") as? ViewController3{
vc.dataFrom1StVC = "message send from 1st VC"
vc.delegate = self
self.navigationController?.pushViewController(vc, animated: true)
}
}
func back(text: String) {
print("data\(text)")
}
}
2nd VC.
protocol backfromSecond: class {
func back(text: String)
}
class ViewController3: UIViewController {
var dataFrom1StVC : String? = nil
week var delegate : backfromSecond?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func DataSendFrom2ndVCTo1stVC(_ sender: AnyObject) {
self.delegate?.back(text: "Message Send From 2nd vc to 1st VC")
self.navigationController?.popViewController(animated: true)
}
}
I hope it will work you. If any problem then ask me i will help you.

Show Tabs with button

I got a TabBarController with two Views in my project. Now I want to set a FirstViewController with two buttons as Initial View Controller when the app launches. The first button should show the FirstView in the TabBarController and the second button the second one. When one of the two buttons is pressed the FirstViewController should disappear and it should only be possible to navigate between the two Views with the Tabs in TabBarViewController.
I did some minor edit, and tested the code I wrote and it works. Control drag from firstButton over to the TabBarController and select Kind as "Show". Then do the same with secondButton.
In your view with the two buttons, I call it First:
import Foundation
import UIKit
class First: UIViewController {
var firstWasClicked = false
#IBAction func firstButtonAction(sender: UIButton) {
firstWasClicked = true
}
#IBAction func secondButtonAction(sender: UIButton) {
firstWasClicked = false
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let controller = segue.destinationViewController as! TabBarController
controller.firstSelected = firstWasClicked
}
}
then in your TabBarController:
import Foundation
import UIKit
class TabBarController: UITabBarController {
var firstSelected = true
override func viewDidLoad() {
if(firstSelected) {
self.selectedIndex = 0
}
else {
self.selectedIndex = 1
}
}
}
This is probably what you want.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func didTapFirst(button: UIButton) {
showViewControllerAt(index: 0)
}
#IBAction func didTapSecond(button: UIButton) {
showViewControllerAt(index: 1)
}
func showViewControllerAt(index: NSInteger) {
let tabBarController = self.storyboard?.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
tabBarController.selectedIndex = index
UIApplication.shared.keyWindow?.rootViewController = tabBarController
}
}
Don't forget to set the Storyboard ID of your UITabBarController.

Resources