How to keep input accessory view up when presenting view controller - ios

I have a container view that is set as the input accessory view for my view controller. Whenever I present a modal view controller the input accessory view dismisses.
I tried using the code below which works when I present the modal view controller. However, that view controller presents an image picker controller and after presenting that image picker controller I get the error "Keyboard cannot present view controllers." Is there a way to keep the input accessory view open for any view controllers presented on top of the base view controller.
let rootViewController: UIViewController = (UIApplication.shared.windows.last?.rootViewController)!
rootViewController.present(addVideoController, animated: true, completion: nil)

I don't think there is a way to keep an inputAccessoryView active through the view hierarchy - either pushing the view onto a navigationController stack or displaying modally will not keep the root's inputAccessoryView visible from my experience. This is because inputAccessoryView is a member of the UIViewController class rather than the window itself - and the new UIViewController you are making active does not have an inputAccessoryView.
I believe you will need to add a inputAccessoryView into the UIViewController class that you are presenting modally. You can set it up the exact same way that you did with the root view controller's class.
// call this in your root view controller that has the inputAccessoryView currently displayed
let addViewController = YourViewControllerClass()
modalViewController.inputAccessoryView = self.inputAccessoryView
self.present(addViewController, animated: true, completion: nil))

Related

viewWillAppear and viewDidAppear not called when presenting view controller from Side Menu?

I'm using this library to show a side menu inside my app: https://github.com/jonkykong/SideMenu
All is fine except for one thing. When I present a viewcontroller from the side menu, and then dismiss this view controller to the main view controller, the viewWillAppear and/or viewDidAppear of the main view controller is not called ever.
From SideMenuVC (side menu view controller) I present other view controller:
let myPortfoliosNC = storyboard!.instantiateViewController(withIdentifier: "myPortfoliosNC")
present(myPortfoliosNC, animated: true, completion: nil)
Next, form the myPortfolioNC i dismiss (from the first view controller) and when go to main view controller the viewDidAppear and viewWillAppear is not called. Any idea of what i'm doing wrong ??

Dismissing presented view controller won't work

I've got a kind of complicated modal segue setup in my project. I'm trying to dismiss a view controller another view controller previously presented. I'm doing so with this code:
if(self.presentedViewController != nil){
print(self.presentedViewController!)
self.presentedViewController!.dismiss(animated: false)
print(self.presentedViewController!)
}
The prints are there for debugging purposes. They show that the presentedViewController doesn't actually get closed.
Even though I've set animated to false, I still see an animation occuring in the app when dismiss is called. Yet, the VC doesn't actually get dismissed.
Anyone knows a solution?
Apple
The presenting view controller is responsible for dismissing the view
controller it presented. If you call this method on the presented view
controller itself, UIKit asks the presenting view controller to handle
the dismissal.
dismiss(animated:completion:) dismisses the view controller that was
presented modally by the view controller.
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621505-dismiss
If you present a view controller from the app's root, for example:
Presenting view controller
let root = UIApplication.shared.keyWindow!.rootViewController!
root.present(someViewController, animated: true, completion: nil)
You would dismiss it from the presented view controller like so:
Presented view controller
let root = UIApplication.shared.keyWindow?.rootViewController
root?.dismiss(animated: true, completion: nil)

No animation when pushing view controllers in UINavigationController

I have a storyboard set up with a UITabBarController which contains a UINavigationController for each tab. For one of the UINavigationControllers there are no transition animations when pushing or presenting a view controller.
There are, at least, two different cases when this happens
1. I have a storyboard segue set up to push the child view controller. The segue triggers when selecting a cell in a table view. The "Animates"-box is checked.
Attempting to programatically push the child view controller yields the same result.
self.navigationController?.pushViewController(nextController, animated: true)
2. There is also no animation when attempting to modally present another view controller from the root view controller of the navigation controller.
modalViewController.modalTransitionStyle = UIModalTransitionStyle.flipHorizontal
self.present(modalViewController, animated: true, completion: nil)
If I present the modalViewController from another view controller the transition is animated which leads me to believe that there is something wrong in the root view controller that is presenting.
Is there a way to disable animations on a UIViewController that I might accidentally have triggered? I have checked and verified that there are no UIView.setAnimationsEnabled(false)
Use self.navigationController?.pushViewController( instead of self.present(
You set up animation in UINavigationController. But you called the function self.present( which is provided by UIViewController. UIViewController of course cannot provide the animation.
In my overridden viewWillDisappear(_ animated: Bool) of the parent view controller I had some code that reset the state of a custom view. The reset did in turn disable actions via CATransaction.setDisableActions(true), thus disabling the transition animations.
Moving the reset to viewDidDisappear(_ animated: Bool) resolved the issue.

Transparent ViewController work with presentViewController, but not pushViewController

let dialog: FriendCheckInDialogViewController = storyboard?.instantiateViewControllerWithIdentifier("FriendCheckInDialogViewController") as! FriendCheckInDialogViewController
dialog.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
If I use
self.navigationController?.presentViewController(dialog, animated: false, completion: nil)
Then transparency works. But popToRootViewControllerAnimated does not, so I cannot go back.
If I use
self.navigationController?.pushViewController(dialog, animated: false)
Then background becomes black instead of transparent. But popToRootViewControllerAnimated works, so I can go back.
What should I do?
You seem to be mixing different presentation styles.
If you present a view controller modally using presentViewController, then you can dismiss it using dismissViewController. In this case you can present the view controller modally over the current view controller.
If you push a view controller onto the navigation controller stack, then you can pop that view controller back off, but the pushed view controller replaces the current view controller, so you can't expose it "underneath".

iOS: UISplitViewController cannot be pushed to UINavigationController

I have an XCode iPad project using a navigation controller. I tried to get a button to push a UISplitViewController to the navigation stack, but got this error:
Split View Controllers cannot be pushed to a Navigation Controller
Turns out UISplitViewController doesn't play nicely with UINavigationController. However, I still need to show the split view controller when this button is clicked. How do I do this? And, also important, how do I make a back button so the user can be returned to the navigation controller?
To display a SplitViewController you'll need to use setRootViewController. This is because a SplitViewController needs to be the root view controller.
From Apple's Documentation:
A split view controller must always be the root of any interface you
create. In other words, you must always install the view from a
UISplitViewController object as the root view of your application's
window. The panes of your split-view interface may then contain
navigation controllers, tab bar controllers, or any other type of view
controller you need to implement your interface.
To get back you'll need to use setRootViewController to go back to the earlier page. I ran into this problem when I converted my iPhone app to universal, and ended up using a navigation controller for the iPhone and setRootViewController for the iPad version. It's a bit of a bummer because you can't animate it nicely without a bit of fudging.
One workaround if you still need to navigate to splitView is to create an empty UIViewController and add the splitViewController as a child
/// This should be in your parent controller
/// that you to navigate your splitView
func navigateToSplit() {
let container = UIViewController()
let splitView = MySplitViewController() // ===> Your splitViewController
container.addAsChildViewController(type: splitView, attached: container.view)
navigationController?.pushViewController(container, animated: true)
}
extension UIViewController {
/// this add a child controller to the view of another controller
func addAsChildViewController(type controller: UIViewController, attached toView: UIView) {
// Add Child View Controller
addChild(controller)
// Add Child View as Subview
toView.addSubview(controller.view)
// Configure Child View
controller.view.frame = toView.bounds
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Notify Child View Controller
controller.didMove(toParent: self)
}
}
Pushing a split view controller through navigation controller is not
possible, but there is a alternative that get the job done
You can create a view controller and add the split view controller as a child and then you can push that created view controller through the navigation controller. It will show your split view controller and you can work with both master and detail.
*remember to add the yoursplitviewcontroller class to custom class in storyboard
note splitcontroller -> (master, detail)
let splitVC = getViewController(storyBoardName: "story board name", viewControllerName: "split view controller identifier") as! yoursplitviewcontroller
view.addSubview(splitVC.view)
view.bounds = splitVC.view.bounds
addChild(splitVC)
func getViewController(storyBoardName: String, viewControllerName: String) -> UIViewController{
let storyBoard = UIStoryboard(name: storyBoardName, bundle: nil)
return storyBoard.instantiateViewController(identifier: viewControllerName)
}
I added a 6th tab containing a SplitView, to my application. On iPad the new tab worked fine when selected, but on iPhone the new tab was moved to the "More…" tab and when selected produced the "Split View Controllers cannot be pushed to a Navigation Controller <UIMoreNavigationController:" message.
I solved the problem by moving the new tab so that it could not fall into the "More…" tab.
A more in depth discussion of the problem can be found at:
Tab Bar Controller with seven tabs, Five tabs lead to Split View Controllers

Resources