I want to navigate from a SKScene to a UIViewController. My code is as follows. However, when the method showViewController() is clicked the view doesn't get navigated. How can I solve this ?
I am using SWIFT3 and XCODE 8.1
class GameScene: SKScene, SKPhysicsContactDelegate {
func showViewController() {
print("button clicked")
self.view!.window!.rootViewController!.performSegue(withIdentifier: "DashboardVIewControllerSegue", sender: self)
}
}
What i have done to acheive this without having memory issue is.
first create some protocol(delegate) in the root viewController. This viewcontroller Contains the view as SKView where we load skscene.
so whenever you want to open a new viewcontroller from the skscene just call the protocol.
here is some code
In mainViewcontroller:
protocol GameProtocol {
func displayViewController()
}
.
extension MainViewController: GameProtocol {
internal func displayViewController() {
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let popoverVC = storyboard.instantiateViewController(withIdentifier: "SettingViewController") as! SettingViewController
// popoverVC.modalPresentationStyle = .fullScreen
// popoverVC.modalPresentationStyle = .popover
popoverVC.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
popoverVC.view.backgroundColor = UIColor.popBackgroundColor
popoverVC.modalPresentationStyle = .popover
popoverVC.popoverPresentationController!.delegate = self
popoverVC.popoverPresentationController!.sourceView = self.view
popoverVC.popoverPresentationController!.sourceRect = CGRect(x: 0.5, y: 0.5, width: 0, height: 0)
popoverVC.preferredContentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
self.present(popoverVC,animated: false,completion: nil)
}
}
I have this code in maincontroller for popup alert when needed. within in gamescene.
and in game scene
func showViewController() {
let viewe = self.view as! GameSceneView
viewe.myDelegate?. displayViewController()
}
Hope you get this.
Related
I am trying to show a custom view on a dismiss of a controller. It's working fine if I am sowing it on popViewController but not working when I am using dismiss method. If anybody knows the solution please help me out.
// presenting screen from HomeController
guard let controller = UIStoryboard(name: "EmptyWorkout", bundle: nil).instantiateViewController(withIdentifier: "LogWoroutVC") as? LogWorkoutViewController else { return }
controller.modalPresentationStyle = .overFullScreen
self.present(controller, animated: true, completion: nil)
// dimissing screen from LogWorkoutViewController
#IBAction func backButtonAction(_ sender: UIButton) {
let window = UIApplication.shared.windows.last
let timerView = UINib(nibName: "WorkoutTimer", bundle: nil).instantiate(withOwner: nil, options: nil).first as? WorkoutTimer
if let timerView = timerView {
let screenSize = UIScreen.main.bounds
let screenWidth = screenSize.width
if let tabBarYPosition = self.tabBarController?.tabBar.frame.origin.y {
let yPosition = tabBarYPosition - 60
timerView.frame = CGRect(x: 0, y: yPosition, width: screenWidth, height: 60)
window?.addSubview(timerView)
}
}
self.dismiss(animated: true, completion: nil)
}
According to the docs, the presenting controller is responsible for the actual dismiss. When the presented controller dismisses itself, it will ask the presenter to do it for it. In here you need to use the closure or protocol. for e.g use like
on your LogWorkoutViewController VC / presented VC declare the variable as like
var dismissedVC : ((Bool) -> Void)?
There is a Boolean property inside UIViewController called isBeingDismissed that you can use for this purpose:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isBeingDismissed {
// TODO: called the closures
dismissedVC!(true)
}
}
on your button action call only dismiss VC
#IBAction func backButtonAction(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
on your HomeController when you present call the closure also.
guard let controller = UIStoryboard(name: "EmptyWorkout", bundle: nil).instantiateViewController(withIdentifier: "LogWoroutVC") as? LogWorkoutViewController else { return }
controller.modalPresentationStyle = .overFullScreen
controller.dismissedVC = { result in
// call your WorkoutTimer view
self.workoutTimer()
}
self.present(controller, animated: true, completion: nil)
func workoutTimer() {
let window = UIApplication.shared.windows.last
let timerView = UINib(nibName: "WorkoutTimer", bundle: nil).instantiate(withOwner: nil, options: nil).first as? WorkoutTimer
if let timerView = timerView {
let screenSize = UIScreen.main.bounds
let screenWidth = screenSize.width
if let tabBarYPosition = self.tabBarController?.tabBar.frame.origin.y {
let yPosition = tabBarYPosition - 60
timerView.frame = CGRect(x: 0, y: yPosition, width: screenWidth, height: 60)
window?.addSubview(timerView)
}
}
}
I have a containerView added to a View Controller. I am hoping to on swipe of the containerView change the view in the container. However when I use the following in my swipe action function it adds the view to the whole page not just changing the view inside the container.
class SwipeDateViewController: UIViewController, UIGestureRecognizerDelegate {
#IBOutlet weak var swipeContainer: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func swipeLeftHandler(_ sender: UISwipeGestureRecognizer) {
let viewController = self.storyboard!.instantiateViewController(withIdentifier: "swipeViewControllerStoryboard") as! SwipeViewController
self.swipeContainer.addSubview(viewController.view)
}
}
How do I just change the view in the container and not update the whole screen?
I think maybe you could add modify function in your custom vc.
Then just run function of it.
For example:
var customVC:EmbeddedViewController?
func addView() {
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "EmbeddedViewController") as! EmbeddedViewController
self.addChild(vc)
vc.view.bounds = CGRect.init(x: 20, y: 40, width: 50, height: 60)
self.view.addSubview(vc.view)
vc.didMove(toParent: self)
customVC = vc
}
#IBAction func actionAddView(_ sender: Any) {
customVC?.changeColor(color: UIColor.black)
}
EmbeddedViewController
class EmbeddedViewController: UIViewController {
public func changeColor(color:UIColor) {
self.view.backgroundColor = color
}
}
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)
Problem State: I've two viewController
parentViewController (375 * 667)
childViewController (300 * 667)
and i want to present childViewController at Axis (75 * 0) as shown below
childViewController is show on this IBAction
#IBAction func btnShowVC(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let newVC = storyboard.instantiateViewController(withIdentifier: "cvc") as? childViewController
self.present(newVC!, animated: true, completion: nil)
}
But it stretches itself like
can anyOne help me to tackle it?
Thanks
You can try in this way.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let newVC = storyboard.instantiateViewController(withIdentifier: "ChildViewController") as? ChildViewController
view.addSubview((newVC?.view)!)
newVC?.view.frame = CGRect(x:75,y:0,width:view.frame.size.width-75,height:view.frame.size.height)
newVC?.view.autoresizingMask = \[.flexibleWidth, .flexibleHeight\]
newVC?.didMove(toParentViewController: self)
Where are you setting the frame of your ViewController? If you are using autolayout you will need to set constraints to make the ViewController look how you want it to. If you want to do it programatically you can set the frame somewhere for example in the code that you posted above you could do this:
#IBAction func btnShowVC(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let newVC = storyboard.instantiateViewController(withIdentifier: "cvc") as? childViewController
newVc.view.frame = CGRect(x: 75, y: 0, width: 300, height: 667)
self.present(newVC!, animated: true, completion: nil)
}
By setting preferredContentSize property will solve your problem, Please try out below code snippet
newVC?.preferredContentSize = CGSize(width: 300, height: 667)
When I try to display a popover view controller programmatically it won't work and I don't know why. I've copied from multiple sources on the web and nothing seems to work, I get the same error in the console every time showing Warning: Attempt to present <AddFriendsPopoverViewController> on <MainPageViewController> whose view is not in the window hierarchy! I am lost and can't seem to figure out what the problem is, thanks in advance!
Here is my swift code in my viewDidLoad() function:
let addFriendsPopoverViewController = AddFriendsPopoverViewController()
override func viewDidLoad() {
super.viewDidLoad()
if (PFUser.currentUser()?["numberOfFriends"])! as! NSObject == 0 {
print(PFUser.currentUser()?["numberOfFriends"])
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("AddFriendsPopoverViewController") as! UIViewController
vc.modalPresentationStyle = UIModalPresentationStyle.Popover
vc.preferredContentSize = CGSizeMake(50, 50)
let popoverMenuViewController = vc.popoverPresentationController
popoverMenuViewController!.permittedArrowDirections = .Any
popoverMenuViewController!.delegate = self
popoverMenuViewController!.sourceView = self.view
popoverMenuViewController!.sourceRect = CGRectMake(
100,
100,
0,
0)
self.presentViewController(vc, animated: true, completion: nil)
}
}
EDIT
I figured out that for a popover to work with iPhone the following code is required.
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .None
}
Your view is not in the view hierarchy until it has been presented and not during viewDidLoad:
Move your code to viewDidAppear:
if (PFUser.currentUser()?["numberOfFriends"])! as! NSObject == 0 {
addFriendsPopoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
addFriendsPopoverViewController.preferredContentSize = CGSizeMake(200, 200)
let popoverMenuViewController = addFriendsPopoverViewController.popoverPresentationController
popoverMenuViewController!.permittedArrowDirections = .Any
popoverMenuViewController!.delegate = self
popoverMenuViewController!.sourceView = self.view
popoverMenuViewController!.sourceRect = CGRect(
x: 50,
y: 50,
width: 1,
height: 1)
presentViewController(
addFriendsPopoverViewController,
animated: true,
completion: nil)
}
Your code is working right but u can not write that presentViewController code in ViewDidLoad method because viewdidLoad call till that time controller itself it not presented thats why it's not allow to presentViewController .
Write that same code in..
override func viewDidAppear(animated: Bool)
{
var controller = UIViewController()
controller.view.backgroundColor = UIColor .greenColor()
presentViewController(controller, animated: true, completion: nil)
}
I have made it simple for multiple use and its ready to use and go. just copy and paste this extension.
extension UIViewController: UIPopoverPresentationControllerDelegate{
#discardableResult func presentPopOver(_ vcIdentifier: String, _ isAnimate: Bool = true,sender:UIView,contentSize:CGSize = .init(width: 100, height: 100)) -> (UIViewController){
let popoverContentController = storyboard?.instantiateViewController(withIdentifier: vcIdentifier)
popoverContentController?.modalPresentationStyle = .popover
if let popoverPresentationController = popoverContentController?.popoverPresentationController {
popoverPresentationController.permittedArrowDirections = .up
popoverPresentationController.sourceView = sender
popoverPresentationController.sourceRect = sender.bounds
popoverContentController?.preferredContentSize = contentSize
popoverPresentationController.delegate = self
if let popoverController = popoverContentController {
present(popoverController, animated: isAnimate, completion: nil)
}
}
return popoverContentController ?? UIViewController()
}
public func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
}
public func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool{
return true
}}
**how to use for presenting pop over on button click:-**
#IBAction func sortClicked(_ sender: UIButton) {
presentPopOver("PopOverVC", sender: sender)
}
***presenting pop over and to get and pass data:-***
#IBAction func sortClicked(_ sender: UIButton) {
let vc = presentPopOver("PopOverVC", sender: sender) as? PopOverVC
vc?.arrayNames = ["name1","name2"]
vc?.callBack = {name in
print(name)
vc?.dismiss(animated: true)
}
}