The screen comes out from behind - swift

I don't know why this is happening, already I have a similar functions on the project and this isn't happening.
When I delete the account and I to the previous screen or if the user is on background and open it again the 2 methods below cause you to be sent to the main screen but I detected this problem (in the picture)
There is the function when I go to the home when I delete the account
private func goToHomeWithLogin(){
let home = HomeAssembly.presenterView()
Utils.getTopViewController()?.present(home, animated: true)
And the getTopViewController do this:
func getTopViewController() -> UIViewController? {
if let viewController = UIApplication.shared.keyWindow?.rootViewController {
if let modal = UIApplication.shared.keyWindow?.rootViewController?.presentedViewController {
return modal
} else if let navigationController = viewController as? UINavigationController {
return navigationController
}
}
return nil
}
When I drag down the screen comes out from behind

looks like default card style of UIViewController.present(...) if you want it full screen (without the swipe down feature) try home.modalPresentationStyle = .fullScreen before presenting it
let home = HomeAssembly.presenterView()
home.modalPresentationStyle = .fullScreen
Utils.getTopViewController()?.present(home, animated: true)

Related

Going from one storyboard to another from a tableView in Swift 5 / Cocoa

have search on that topic without finding a solution that work.
I am building a accounting application with several storyboard. Main, Customer( clients), invoice (factures)... etc. I can go from the main storyboard to the customer of Invoice storyboard by click a button no problem... The button (main SB) is linked to the Customer or Invoice storyboard reference.
In the clients storyboard, I have a tableView with that list the purchased historic of that customer. I would like to to be able to double clic on a specific invoice, and open that invoice in the Invoice storyboard.
The double clic part work fine, print message work... but the program crash after with the message: Could not cast value of type '__NSCFBoolean' (0x7fffaab000c8) to '__C.NSViewControllerPresentationAnimator'
That code was taken andadapted from another post. I have tried different variation withou success ie same error message.
I have not work on the part where I transfer the Invoice number from the client SB to the Invoice SB. I will likely transfer the Invoice number with a segue and have the Invoices program look if that variable if not nil, after loading
Invoice storyboard filename : factures.storyboard
facture ViewController Class : FacturesVC
ViewController storyboardID : facturesVC_id
#objc func tableViewDoubleClick(_ sender:AnyObject) {
if tableView.selectedRow >= 0 {
print ("VC545:", tableView.selectedRow)
//let storyboard = NSStoryboard(name: "factures", bundle: nil)
//let VC = storyboard.instantiateViewController(withIdentifier: "facturesVC_id") // give same error
let VC = NSStoryboard(name: "factures", bundle: nil).instantiateController(withIdentifier: "facturesVC_id") as! FacturesVC
self.present(VC as NSViewController, animator: true as! NSViewControllerPresentationAnimator)
}
}
Your code does not make sense.
It looks like you are trying to call present(_:animator:). If you call that, you need to pass it an animator (an object of type NSViewControllerPresentationAnimator.)
Your code does not create a NSViewControllerPresentationAnimator.
Here is an outline of how you need to change it:
let vc = NSStoryboard(name: "factures", bundle: nil).instantiateController(withIdentifier: "facturesVC_id") as! FacturesVC
let animator = // Code to create an NSViewControllerPresentationAnimator
self.present(vc, animator: animator)
I haven't worked with NSViewControllerPresentationAnimators before. (I mostly work with iOS these days.) You should probably search for tutorials on NSViewControllerPresentationAnimator if you are unsure how to proceed.
Finally, I have found the answer I was looking for...
Here is the code.
#objc func tableViewDoubleClick(_ sender:AnyObject) {
if tableView.selectedRow >= 0 {
let srow = tableView.selectedRow
//print ("VC551:", srow)
fact_nb = Int(fact_tbv[srow].id_f) ?? 0 // invoice nb that you want to segue
let storyboard = NSStoryboard(name: "factures", bundle: nil)
let VC = storyboard.instantiateController(withIdentifier: "facturesVC_id")
//self.presentAsSheet(VC as! NSViewController) work fine for sheet
// self.presentingViewController // data are laoded but nothing show up
// self.presentAsModalWindow(VC as! NSViewController) // OK for modal, cannot be resize , yellow button missing on bar
// self.present(VC as! NSViewController, animator: false as! NSViewControllerPresentationAnimator) // true or false... need a animator
let window = NSWindow(contentViewController: VC as! NSViewController)
window.center()
let windowController = NSWindowController(window: window)
windowController.showWindow(nil)
//see How to Perform Segue https://www.youtube.com/watch?v=JL0xuZ4TXrM
self.performSegue(withIdentifier: "gotofact", sender: nil) // segue identifier name : gotofact
}
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
let sb = segue.destinationController as! FacturesVC
print ("VC569:", fact_nb)
sb.factnb = fact_nb
}

Is it possible to observe changes in presentingViewController?

Is there any equivalent in Swift to RACObserve(self, presentingViewController)?
Or any other why to imitate this behaviour?
My issue is that I want to be notified whenever a view controller is "hidden" by another view controller. In objc what I'd do is to check if self.presentingViewController is nil.
Note that in this scenario there's no knowledge of which view controller is presented, so it's impossible to notify from within its viewDidAppear/viewDidDisappear.
As I understand your question: you need to to know which view controller is presented now and you need notification inviewDidAppear/viewDidDisappear.
So we can get this in several way.
The simple way is:
Get information of which is the top ViewController right now.
2.Call this method in your viewDidAppear/viewDidDisappear
Like this :
Get Which is The Top ViewController
func getTopViewController() -> UIViewController? {
if var topVC = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topVC.presentedViewController {
topVC = presentedViewController
return topVC
}
return topVC
}
return nil
}
Call in viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
if let top = getTopViewController() {
print("topView Controller name \(top.title)")
top.view.backgroundColor = .red
}
}
Hope it will help you !

NavigationController nested in TabController animation bug

I try my best to explain what is happening.
I have updated the XCode to Version 10.1 (10B61)
And the iOS on my iPhone and Simulator is v12.1
My app has a TabController with 5 tabs.
First: Posts
Fifth: Profile Posts
These are embedded into a navigation controller (In case someone
clicks on the comments button)
So. I've noticed that if I run my app and I click the comments, it pushes that vc in a weird way to the screen, then clicking back just "bumps" back. Also slide back isn't working.
However, if I switch tabs first then everything works fine.
VIDEO:
https://www.youtube.com/watch?v=fgS3j21L8Js
As you see in the video everything is fine after switching to Profile Posts + back .
UPDATE 1:
So if I start my app, switch to another Tab, then back to the original, it works fine.
Requested code:
func commentsButtonTapped(sender: UIButton) {
let touchPoint:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint) {
openDetails(indexPath: indexPath, shouldShowKeyboard: false)
}
}
func openDetails(indexPath: IndexPath, shouldShowKeyboard : Bool) {
if (self.tableView.cellForRow(at: indexPath) as? WorldMessageCell) != nil {
let storyboard = UIStoryboard(name: "Additional", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "DetailsViewController") as! DetailsViewController
vc.postId = PostIds.shared.nearby.ids[safe: indexPath.row]
vc.shouldShowKeyboard = shouldShowKeyboard
self.navigationController?.pushViewController(vc, animated: true)
}
}
UPDATE 2:
Solved the problem by forcing the TabController to switch between tabs..
override func viewDidAppear(_ animated: Bool) {
self.selectedIndex = 1
self.selectedIndex = 0
}
But that's not how it should work..
UPDATE 3:
I have tested it, if I make the navigation controller->vc the initial vc (so no tab controller) everything works fine.
But as soon as the navigationcontroller is nested inside the tab, it happens.
I made a new project to test if this is a version specific bug but no, everything works fine there. So the issue must be with my app.
What could generate issue like that (in the video)?
Ohh.. I have found the problem & bug:
So if you have navigation controllers nested into a tab controller that calls it's viewDidLoad() function, then the navigation controller will have problems.
The code I had to remove totally:
override func viewDidAppear(_ animated: Bool) {
// here i had some code ... /
}
Now everything works..

Remove/Hide UITabBarItem in Swift

I have looked really hard for this solution in Swift but am not coming up with one that works for me. I am trying to hide my "Admin" TabBarItem based on the permissions of the person that logs in to the app. I can disable it but it still shows up on the bar. I want to be able to show it for certain people and hide it for others. Also, when I print self.tabBarController?.viewControllers I get nil.
class TabBarMenuController: UITabBarController {
let ref = Firebase(url: "")
var position = ""
func getPosition() {
let userRef = ref.childByAppendingPath("users/\(ref.authData.uid)")
userRef.observeSingleEventOfType(.Value, withBlock: {snapshot in
if snapshot.value["position"] as! String != "Staff" {
self.position = snapshot.value["position"] as! String
}
})
}
override func viewWillAppear(animated: Bool) {
getPosition()
print(self.tabBarController?.viewControllers)
if position != "Staff" {
if let tabBarController = self.tabBarController {
let indexToRemove = 3
if indexToRemove < tabBarController.viewControllers?.count {
var viewControllers = tabBarController.viewControllers
viewControllers?.removeAtIndex(indexToRemove)
tabBarController.setViewControllers(viewControllers, animated: true)
}
}
}
}
Also, I keep reading that this is against Apple's intended use. Is that true still? Is there a better workflow to accomplish that type of functionality?
I would create a tab that opens up the user's account and have a button in the user VC tab that opens up a page for admins only. you can show and hide the button as needed using adminButton.hidden = true or adminButton.hidden = false.

Swift popToViewController

Good day guys, I'm learning Swift, needed some help here.
The user are signing up and selected their image. Upon dismissing the image picker, I would like to have the ComposeViewController appear.
Here is the code:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: NSDictionary!) {
let pickedImage:UIImage = info.objectForKey(UIImagePickerControllerOriginalImage) as UIImage
//Scale Down Image
let scaledImage = self.scaleImageWith(pickedImage, and: CGSizeMake(100,100))
let imageData = UIImagePNGRepresentation(scaledImage)
let imageFile:PFFile = PFFile(data: imageData)
PFUser.currentUser().setObject(imageFile, forKey: "profileImage")
PFUser.currentUser().saveInBackgroundWithTarget(nil, selector: nil)
picker.dismissViewControllerAnimated(true, completion: nil)
//this is the line seems to have problem.
self.navigationController?.popToViewController(ComposeViewController, animated: true)
}
Then I got these error:
ComposeViewController.Type' is not convertible to 'UIViewController
Expected member name or constructor call after type name
It has suggestion to fix by putting () after ComposeViewController but then it gives out more errors after fixing.
Hope someone could help. Thanks! :-)
let controllers = self.navigationController?.viewControllers
for vc in controllers! {
if vc is YourVC {
_ = self.navigationController?.popToViewController(vc as! YourVC, animated: true)
}
}
I know this is old, but it's like what Saqib said, you can't pop to a viewcontroller that doesn't exist yet.
A lot of the answers here seem to be from people that didn't read your question, just the title. I'll leave this code here in case it helps anyone.
let vcIndex = self.navigationController?.viewControllers.indexOf({ (viewController) -> Bool in
if let _ = viewController as? ComposeViewController {
return true
}
return false
})
let composeVC = self.navigationController?.viewControllers[vcIndex!] as! ComposeViewController
self.navigationController?.popToViewController(composeVC, animated: true)
There's a method that lets you get access to an array of all the ViewControllers on the current stack, and you can capture the one you want by using its index, for instance:
let switchViewController = self.navigationController?.viewControllers[1] as! ComposeViewController
self.navigationController?.popToViewController(switchViewController, animated: true)
if let composeViewController = self.navigationController?.viewControllers[1] {
self.navigationController?.popToViewController(composeViewController, animated: true)
}
I ended up replaceing the following code inside the main view and it works. I'm not sure if this is the right way, would you mind giving me some comments?
//self.navigationController?.popToViewController(ComposeViewController, animated: true)
let switchViewController = self.storyboard?.instantiateViewControllerWithIdentifier("view2") as ComposeViewController
self.navigationController?.pushViewController(switchViewController, animated: true)
I defined "view2" as the destination storyboard ID.
What I found more useful was to do a first lookup with viewControllers, that way you get the first instance you find in the stack, without having to guess the actual index.
e.g.
let mainViewControllerVC = self.navigationController?.viewControllers.first(where: { (viewcontroller) -> Bool in
return viewcontroller is ComposeViewController
})
if let mainViewControllerVC = mainViewControllerVC {
navigationController?.popToViewController(mainViewControllerVC, animated: true)
}
For Swift 4.0 and above Using Filter
guard let VC = self.navigationController?.viewControllers.filter({$0.isKind(of: YourViewController.self)}).first else {return}
self.navigationController?.popToViewController(VC, animated: true)
navigation controller maintains the stack of views you are pushing. Its like a Last in first out queue.
In order to pop to ComposeViewController, that view must already exist in the queue and you should have reference to it.
You will need to pass the instance of ComposeViewController. for simplicity you might save that reference in appdelegate. (this approach is not recommended)
for (var i = 0; i < self.navigationController?.viewControllers.count; i++)
{
if(self.navigationController?.viewControllers[i].isKindOfClass(DestinationViewController) == true)
{
self.navigationController?.popToViewController(self.navigationController!.viewControllers[i] as! DestinationViewController, animated: true)
break;
}
}
In Swift 4.1 and Xcode 9.4.1
Suppose if you moved from 1st ViewController to 2nd, then 2nd to 3rd. Now if you want to come back from 3rd to 1st directly this code is enough.
if let composeViewController = self.navigationController?.viewControllers[1] {//Here you mention your view controllers index, because navigation controller can store all VC'c in an array.
print(composeViewController)
self.navigationController?.popToViewController(composeViewController, animated: true)
}