About
I'm developping ios app with MXParallaxHeader.
I use it in order to create twitter-like UI.
However, I don't know how to pass data from MXScrollView to childViewController when I go MXScrollView page.
Question
How could I pass data from MXScrollView to childViewController?
Sample Code
PreviousViewController
//MXScrollViewController=ParentVC of MarkerInfoTabViewController
class PreviousViewController:UIViewController {
.
.
#IBAction func goMXScrollView(_ sender: Any) {
let nextView = self.storyboard?.instantiateViewController(withIdentifier: "MXScrollViewController") as! MXScrollViewController
self.navigationController?.pushViewController(nextView, animated: true)
}
}
childViewController
//MarkerInfoTabViewController(=childVC of MXScrollView)
import Tabman
import UIKit
import MXParallaxHeader
class MarkerInfoTabViewController: TabmanViewController {
var marker:Marker!
private var viewControllers = [UIViewController?]()
override func viewDidLoad() {
super.viewDidLoad()
let leftView = self.storyboard?.instantiateViewController(withIdentifier: "MarkerInfoLeftViewController") as! MarkerInfoLeftViewController
let rightView = self.storyboard?.instantiateViewController(withIdentifier: "MarkerInfoRightViewController") as! MarkerInfoRightViewController
//↓I want to pass data here
leftView.marker = marker
viewControllers = [leftView, rightView]
self.dataSource = self
// Create bar
let bar = TMBar.ButtonBar()
bar.layout.transitionStyle = .snap // Customize
// Add to view
addBar(bar, dataSource: self, at: .top)
}
}
My App Image
・storyboard
・segue to header
・segue to childVC
Reference
My app is mostly the same as this app.
Just define a property in the child controller class
class ChildViewController {
var passedData: MY_DATA_TYPE
...
and set it after the instantiation
let nextView = self.storyboard?.instantiateViewController(withIdentifier: "ChildViewController") as! ChildViewController
nextView.passedData = MY_PASSED_DATA
self.navigationController?.pushViewController(nextView, animated: true)
Related
I have UIViewController and how I can to convert UIViewController to Class.swift. Class is initialized...
MainController.staticInstance.viewControllers?[1] as! Destination
MainController is class which extending UITabBarController. I want to get child controller from UITabBar and convert it to Class which parent.
Clearly example:
class MainController: UITabBarController {
override func viewDidLoad() {
(self.viewControllers?[1] as! Destination).itsMyFunction();
}
}
MAXIMUM DETAIL:
1 class
class First: UIViewController {
func itsMyFunction() {
print("Hello world!")
}
}
this is Class I attach to class in STORYBOARD!
2 class
class MainController: UITabBarController {
func override viewDidLoad() {
// Here I set index UITabBar ITEM which attach to MAIN UiTabBarController
self.selectedIndex = 0
// NOW I want to get INSTANCE CLASS First
(self.viewControllers?[1] as! First).itsMyFunction();
}
}
Can you please follow this setup example?
class TabBarViewController: UITabBarController {
let firstVC = First()
let secondVC = SecondViewController()
override func viewDidLoad() {
super.viewDidLoad()
firstVC.tabBarItem = UITabBarItem(tabBarSystemItem: .search, tag: 0)
secondVC.tabBarItem = UITabBarItem(tabBarSystemItem: .more, tag: 1)
let tabBarList = [firstVC, secondVC]
viewControllers = tabBarList
if let destination = viewControllers?.first as? First {
destination.itsMyFunction()
}
}
}
It seems that you fail to get the Class instance of the controller because your viewControllers array is empty based on the code that you posted. Let me know if it worked.
That way you get a crash if the type is something different. Try to avoid using ! whenever you can.
Use a weak cast and evaluate the unwrapped type if its yours.
if let destination = destMainController.staticInstance.viewControllers?.first as? Destination {
destination.itsMyFunction()
}
I'm following this tutorial link
But with one change that I made since the beginning.
I Added a ViewController (and made it the Initial View Controller) and Added a Container View in it.
Then I embed seagued between my View Container and the tutorial's SplitViewController.
And all worked well, until I got to this step:
Go to to AppDelegate.swift and replace the implementation of application(_:didFinishLaunchingWithOptions:) with the following:
guard let splitViewController = window?.rootViewController as? UISplitViewController,
let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
let masterViewController = leftNavController.topViewController as? MasterViewController,
let detailViewController = splitViewController.viewControllers.last as? DetailViewController
else { fatalError() }
let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstMonster
return true
How this code should be modified to work with my case?
In your case you can't get access to uisplitviewcontroller in AppDelegate. Since you are using Container Embedded view like in image below. You get reference of the UISplitviewcontroller from prepareFor segue of your first viewController. So instead of writing code in AppDelegate, try do that in prepare for segue in your initial viewController.
Initial ViewController
class ViewController: UIViewController {
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "embedseg" {
guard let splitViewController = segue.destination as? UISplitViewController,
let leftNavController = splitViewController.viewControllers.first as? UINavigationController,
let masterViewController = leftNavController.topViewController as? MasterViewController,
let rightNavController = splitViewController.viewControllers.last as? UINavigationController,
let detailViewController = rightNavController.topViewController as? DetailViewController
else { fatalError() }
let firstMonster = masterViewController.monsters.first
detailViewController.monster = firstMonster
masterViewController.delegate = detailViewController
detailViewController.navigationItem.leftItemsSupplementBackButton = true
detailViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}
}
}
There is such code, if user logged on - ViewController changes :
func ifLogged() {
let preferences = UserDefaults.standard
let token = "token"
if preferences.object(forKey: token) == nil {
// Doesn't exist and stop at the same viewController
} else {
let newViewController = GeneralChooser()
self.navigationController?.pushViewController(newViewController, animated: false)
// push new generalChooser when logged
}
}
But in this case I do not see view elements, just background color from ViewHelper class
class GeneralChooser: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
ViewHelper.BackGroundColor(view: self.view)
There is BackgroundColor func below
class func BackGroundColor(view: UIView){
let startColor = UIColor(red:0.15, green:0.50, blue:0.70, alpha:1.0)
let endColor = UIColor(red:0.58, green:0.65, blue:0.81, alpha:1.0)
let newLayer = CAGradientLayer()
newLayer.colors = [startColor.cgColor,endColor.cgColor]
newLayer.zPosition = -1
newLayer.frame = view.frame
view.layer.addSublayer(newLayer)
If i do not call this function in GeneralChooser class, the screen is black and there are not view elements, but in initial ViewController i see view elements, just background color is default.
What am I doing wrong. Thanks for all.
The problem is in this line
let newViewController = GeneralChooser()
this line doesn't load xib or reference the storyboard object associated with that class
Use instantiateViewController and give the viewController storyboard ID in storyboard say GeneralChooserView
let vc = self.storyboard?.instantiateViewController(withIdentifier:"GeneralChooserView")
self.navigationController?.pushViewController(vc!, animated: true)
Or if you are using xibs with GeneralChooser as xib file for GeneralChooser class
let vc = GeneralChooser(nibName: "GeneralChooser", bundle: nil)
self.navigationController?.pushViewController(vc, animated: true)
I have made delegate protocol within two view controllers. but the delegate method doesn't call on my code snippet. what is the reason for that. I couldn't find out the issue kindly post your suggestions to relive this issue.
Main View controller
class ViewController: UIViewController, testDelegateMethod {
override func viewDidLoad() {
super.viewDidLoad()
let vw = testViewController()
vw.delegateTest = self
let push = self.storyboard?.instantiateViewController(withIdentifier: "testViewController")
self.navigationController?.pushViewController(push!, animated: true)
}
func testMethod(value:String) {
print("Hai", value)
}
}
Sub View controller
protocol testDelegateMethod {
func testMethod(value:String)
}
class testViewController: UIViewController {
var delegateTest : testDelegateMethod?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func actSubmit(_ sender: Any) {
delegateTest?.testMethod(value: "Hello how are you!")
}
}
The issue you are facing due to this line
let vw = testViewController()
vw.delegateTest = self
You have created instance of testViewController vw, and Assigned delegate of vw instance
In the next line
let push = self.storyboard?.instantiateViewController(withIdentifier: "testViewController")
self.navigationController?.pushViewController(push!, animated: true)
You are creating different instance of testviewcontroller push
There is no need of this code,
let vw = testViewController()
vw.delegateTest = self
Instead do
let push testViewController = self.storyboard.instantiateViewController(withIdentifier: "testViewController") as! testViewController
push.delegateTest = self
self.navigationController?.pushViewController(push, animated: true)
Update these changes in viewdidLoad() method
override func viewDidLoad() {
super.viewDidLoad()
if let push = self.storyboard?.instantiateViewController(withIdentifier: "testViewController") as? SelectionScreen
{
push.delegateTest = self
}
}
This code snippet does not make sense. You just create an object but does not use it further. So remove this code snippet.
let vw = testViewController()
vw.delegateTest = self
And do like this:
override func viewDidLoad() {
super.viewDidLoad()
let pushVC = self.storyboard?.instantiateViewController(withIdentifier: "testViewController") as! testViewController
pushVC.delegateTest = self
self.navigationController?.pushViewController(pushVC, animated: true)
}
I think, you put code func testMethod(value:String) {
print("Hai", value)
}
into viewDidLoad and above let push = self.storyboard?.instantiateViewController(withIdentifier: "testViewController")
self.navigationController?.pushViewController(push!, animated: true)
let vw = testViewController() // Your are doing wrong code
vw.delegateTest = self
Use only this
I hope it will work for you
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let push = storyboard.instantiateViewController(withIdentifier:"testViewController")as! testViewController
push.delegateTest = self
self.navigationController?.pushViewController(push, animated: true)
Summary:
I am able to get a full-screen popover but NOT a custom-size popover through a button action within a custom table cell. I am able to get it working though when the button is not within a custom cell. Upon debugging it seems that when the button is within the custom table cell the delegate object of the popoverPresentationController is not being called which is the one that resizes the popover window.
Details:
Following is the code that works when button is outside of UITableViewCell:
import UIKit
import AVKit
import CoreGraphics
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
// This delegate function ensures that popup size is constrained to
// what's specified in preferredContentSize earlier.
return UIModalPresentationStyle.none
}
// This is triggered by a button in UIViewController.. nothing to do
// with the UITable here. This implementation works.
#IBAction func buttonpressed(_ sender: AnyObject) {
let sb = self.storyboard
let vc: AnyObject! = sb!.instantiateViewController(withIdentifier: "popover")
let pc = vc as! PopOverWindow
pc.modalPresentationStyle = UIModalPresentationStyle.popover
pc.preferredContentSize = CGSize(width: 100, height: 100)
// Needs to be called BEFORE we access
// popoverPresentationController below. Counter-intuitive but this
// is how apple docs recommend it
self.present(pc, animated: true, completion: nil)
let popover = pc.popoverPresentationController
popover?.permittedArrowDirections = UIPopoverArrowDirection.any
popover?.delegate = self
let button = sender as! UIButton
// Need both statements below so that popover knows where to be
// tethered
popover?.sourceView = sender as? UIView
// the position of the popover where it's showed
// do not use buttons.frame
popover?.sourceRect = button.bounds
}
Important function here is adaptivePresentationStyle() which makes sure that the popup is not full screen.
Now, let's try to the same in a custom UITableViewCell. Biggest change here is that UITableViewCell is NOT a descendant of UIViewController
#IBAction func infoButtonTouchDown(sender: AnyObject) {
let sb = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let vc: AnyObject! = sb.instantiateViewControllerWithIdentifier("popover")
let pc = vc as! PopOverWindow
pc.modalPresentationStyle = .Popover
pc.preferredContentSize = CGSizeMake(50,100)
// Custom View Cell is not UIViewController so I need to following
// to be able to call presentViewController later
// I could have also done
//self.window!.rootViewController?.presentViewController(..)
// but the results were the same
let t = self.window?.rootViewController as! UITabBarController
let n = t.selectedViewController as! UINavigationController
let m = n.visibleViewController as! MyTableViewController
// Important: this needs to be called BEFORE we access
// pc.popoverPresentationController object. Apple Docs say it.
m.presentViewController(pc, animated: true, completion: nil)
let popover = pc.popoverPresentationController
popover?.permittedArrowDirections = UIPopoverArrowDirection.Any
// I tried doing popover?.delegate = d to make the underlying table
// as the delegate object but the results were same
popover?.delegate = self
let viewForSource = sender as! UIView
popover?.sourceView = m.view
// the position of the popover where it's showed
// just some random position in view.
popover?.sourceRect = CGRectMake(100,100,1,1)
}
The TROUBLE in above code is that the delegate function adaptivePresentationStyle() is not being called and consequently I end up getting a full-screen popover and not a half-screen.
Any help is hugely appreciated!