I have this code for a button that when clicked takes the user to the home page which is a UIViewController I have named 'HomePageViewController', I have also set the class as seen:
class set up.
The button code is located in the first (initial controller) UIViewController called 'SignInViewController', when it is clicked I want the HomePageViewController to replace the SignInViewController:
#IBAction func btnSignInPressed(_ sender: UIButton) {
// if true take to home page
DispatchQueue.main.async {
let home = self.storyboard?.instantiateViewController(identifier: "HomePageViewController") as!
HomePageViewController
// replace the homepage as the root page
let appDelegate = UIApplication.shared.delegate
appDelegate?.window??.rootViewController = home
}
}
However, when I run this in stimulator, the button does not do anything, when I click it. Just a note, I am using a Tab Bar Controller, so I tried setting the root to the UIBarController, however this also did not work.
In your appDelegate, add property:
final var window: UIWindow?
Call it like this
#IBAction func btnSignInPressed(_ sender: UIButton) {
// if true take to home page
DispatchQueue.main.async {
let home = self.storyboard?.instantiateViewController(identifier: "HomePageViewController") as!
HomePageViewController
let window = UIApplication.shared.delegate!.window!!
window.rootViewController = nil
window.rootViewController = home
UIView.transition(with: window, duration: 0.4, options: [.transitionCrossDissolve], animations: nil, completion: nil)
}
}
Related
Similar like iPhone phoneBook, I want make view like VC(tableView) -> Modal -> navigationView. But I'm having some problems:
//vc(tableView)
#objc func addBtnClick(sender: UIButton){
let childVC = InformationView()
let fakeRootView = UINavigationController(rootViewController: childVC)
self.present(fakeRootView, animated: true){
print("rootView CompletionHandler")
}
Then save infomation in InformationView using realm:
#objc
func saveBtnClick(sender: UIButton){
content.phoneName = self.nameField.text!
content.phoneNum = self.phoneNumber.text!
try! realm.write {
realm.add(content, update: .all)
}
print(Realm.Configuration.defaultConfiguration.fileURL!)
table.tableView.reloadData()
self.presentingViewController?.dismiss(animated: true)
navInfoViewLoad()
func navInfoViewLoad(){
let childVC = contentView
self.navigationController?.pushViewController(childVC, animated: true)
}
After pressing saveBtnClick, I want to move to contentView. But I am getting an error:
Thread 1: Pushing a navigation controller is not supported
What is the problem?
I used 'LGSideMenuController' in my project. but it cannot open from my all viewcontroller. I want to open sidemenu in all my viewcontroller in my project. But right now I am able to open it from my 'HomeViewcontroller' and only for one time.
In my AppDelegete.swift file I make function and it called in otpviewcontroller.
func createSideMenu(){
let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
let rootviewcontroller = storyBoard.instantiateViewController(withIdentifier: "HomeVC") as! HomeVC
let navigation = UINavigationController.init(rootViewController: rootviewcontroller)
let sideMenuVC = storyBoard.instantiateViewController(withIdentifier: "SideMenuVC") as! SideMenuVC
let sideMenuController = LGSideMenuController(rootViewController: navigation,
leftViewController: sideMenuVC,
rightViewController: nil)
sideMenuController.leftViewWidth = 280.0
sideMenuController.leftViewPresentationStyle = .scaleFromBig
self.window?.rootViewController = sideMenuController
self.window?.makeKeyAndVisible()
}
In my 'Homeviewcontroller' and otherviewcontroller I open sidemenu like this.
#IBAction func sideMenuAction(_ sender: UIBarButtonItem) {
self.sideMenuController?.showLeftView(animated: true, completionHandler: nil)
}
It open in only HomeViewcontroller but I want to open it in all Viewcontroller of my project. I am new in swift. Please help me. Thank you.
You can use the same method to open "LGSideMenuController" as you did in "HomeViewcontroller".
Suppose in another viewcontroller, you want to open "LGSideMenuController" on click of button event then code will look like
#IBAction func openSideMenu(_ sender: Any) {
self.sideMenuController?.showLeftView(animated: true, completionHandler: nil)
}
Edit Answer
I checked your code and found that you are trying to present another viewcontroller screen over "LGSideMenuController" instead of using push transition.
Please change your code in SideMenuVC controller as below
#IBAction func eventsAction(_ sender: Any) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "EventsVC") as! EventsVC
//let navigationController = UINavigationController(rootViewController: vc)
//self.present(navigationController, animated: true, completion: nil)
self.sideMenuController?.hideLeftViewAnimated()
self.sideMenuController?.rootViewController?.show(vc, sender: self)
}
In the above code, i hide the sidemenu first and then push "EventsVC" view controller in sideMenuController. Please apply the same code on other button actions.
Hope it helps.
I want to click the Sign Out button on the ListViewController to sign out the user, and return to the SignInViewController, like below picture.
In ListViewController for the SignOut button:
#IBAction func didTapSignOut(_ sender: Any) {
//Sign Out
GIDSignIn.sharedInstance().signOut()
//Go to the `SignInViewController`
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desVC = mainStoryboard.instantiateViewController(withIdentifier: "SignInViewController") as! SignInViewController
self.navigationController?.pushViewController(desVC, animated: true)
}
When back to the SignInViewController, there's a back button, which is directed back to the ListViewController on it. It seems like the app still has the cache of the user's data so the user doesn't actually sign out.
But what I want is to go back to the app's initial state that the user has to sign in again.
My Storyboard:
How I move from SignInViewController to ListViewController: in AppDelegate
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
if let error = error {
print("\(error.localizedDescription)")
} else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabbarVC = storyboard.instantiateViewController(withIdentifier: "TabbarIdentifier") as! UITabBarController
self.window?.rootViewController?.present(tabbarVC, animated: false, completion: nil)
}
}
Solution I've tried:
var window: UIWindow?
#IBAction func didTapSignOut(_ sender: Any) {
GIDSignIn.sharedInstance().signOut()
let desVC: UIViewController = SignInViewController()
if let window = self.window{
window.rootViewController = desVC
}
self.navigationController?.popToRootViewController(animated: true)
}
but now the view didn't change after I clicked the button.
In google login you are presenting the tabbar controller from signinViewcontroller. So just dismiss the tabbar controller when logout button is tapped
#IBAction func didTapSignOut(_ sender: Any) {
//Sign Out
GIDSignIn.sharedInstance().signOut()
//Go to the `SignInViewController`
self.tabBarController?.dismiss(animated: true, completion: nil)
}
change self.navigationController?.pushViewController to self.navigationController?.popToRootViewController (this will have a pop animation)
if you need a push animation, use self.navigationController?.setViewControllers([desVC])
UPDATED 1:
If you don't mind having no push/pop animation, you can directly change the window
let nvc = UINavigationController(rootViewController: desVC)
let window = UIApplication.shared.window
window.rootViewController = nvc
UPDATED 2:
Yea, updating via navigationController would not be proper in your hierarchy. Just change the rootViewController of the window (as stated in Updated 1)
I have the tabBar below and each of those TabBars belongs to it's own specific UIViewController . My issue is with my Home Tab Bar . That TabBar has a TableView if I am in another TabBar item like 'Search' or 'Notification' and go back to my Home tab Bar item then I want my TableView to remain in the same place . I have been able to do that by calling this
controller.dismiss(animated: false, completion: nil)
however as you can see from the image below my Home Tab Bar item does not get highlighted and I created a method that attempts to get my Home Tab highlighted but I get a nil exception . First let me show you my custom function all Tab Bar items on click go through here
class HomeProfile: NSObject {
var mycontroller = ControllerEnum()
func TabBarLogic(_ tabBar: UITabBar, didSelect item: UITabBarItem, streamsModel: Int, controller: UIViewController) {
if tabBar.items?.index(of: item) == 0 {
tabBar.tintColor = UIColor(hexString: "#004d99")
if TabBarCounter == 0 {
// To Refresh
let nextViewController = controller.storyboard?.instantiateViewController(withIdentifier: "HomeC") as! HomeC
controller.present(nextViewController, animated:false, completion: nil)
} else {
// keeps TableView position but does not highlight Tab
controller.dismiss(animated: false, completion: nil)
let Home = HomeC()
Home.HighlightTabBar() // Nil exception here
TabBarCounter = 0
}
}
if tabBar.items?.index(of: item)! == 1 {
// Search Tab Item
tabBar.tintColor = UIColor(hexString: "#004d99")
let nextViewController = controller.storyboard?.instantiateViewController(withIdentifier: "LocalSearchC") as! LocalSearchC
controller.present(nextViewController, animated:false, completion:nil)
TabBarCounter = 1
}
if tabBar.items?.index(of: item)! == 2 {
// Post
}
if tabBar.items?.index(of: item)! == 3 {
// Notification
}
if tabBar.items?.index(of: item)! == 4 {
// Menu
}
}
}
This functionality is meant to be similar to facebook, if you are on the HomePage and click the Home Tab again then it will refresh the TableView however if you are on another Tab and go back to the Home tab it'll maintain your position; The TabBarCounter checks on that .
Ok this is my Home Controller code for the Tab
class HomeC: UIViewController,UITableViewDataSource,UITableViewDelegate, UITabBarDelegate{
#IBOutlet weak var TabBar: UITabBar!
override func viewDidLoad() {
super.viewDidLoad()
TabBar.delegate = self
TabBar.selectedItem = TabBar.items![0]
TabBar.tintColor = UIColor(hexString: "#004d99")
}
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
homeProfile.TabBarLogic(tabBar, didSelect: item, streamsModel: TabCounter,controller: self)
}
func HighlightTabBar() {
TabBar.delegate = self
TabBar.selectedItem = TabBar.items![0] // this fails
TabBar.tintColor = UIColor(hexString: "#004d99")
}
}
I know that the reason why it fails is because the TabBar in HighlightTabBar() when calling it does not have the reference to the TabBar . How can I make it so that this works . I have been looking at this one How to programmatically change UITabBar selected index after Dismiss? but so far nothing works .
Put the code in App delegate or button action
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let tabBarController = appDelegate.window?.rootViewController as! UITabBarController
tabBarController.selectedIndex = 2
I need to present a modal VC that sets a property in my presenting VC, and then I need to do something with that value back in the presenting VC. I have to be able to pass pointers to different properties to this function, so that it's reusable. I have the code below (KeyPickerTableViewController is the modal VC).
It should work, except not, because the line after present(picker... gets executed immediately after the picker is presented.
How do I get my presenting VC to "wait" until the modal VC is dismissed?
#objc func fromKeyTapped(_ button: UIBarButtonItem) {
print("from tapped")
setKey(for: &sourceKey, presentingFrom: button)
}
#objc func toKeyTapped(_ button: UIBarButtonItem) {
print("from tapped")
setKey(for: &destKey, presentingFrom: button)
}
fileprivate func setKey(for key: inout Key!, presentingFrom buttonItem: UIBarButtonItem) {
let picker = KeyPickerTableViewController()
picker.delegate = self
picker.modalPresentationStyle = .popover
picker.popoverPresentationController?.barButtonItem = buttonItem
present(picker, animated: true, completion: nil)
if let delKey = delegatedKey {
key = delKey
}
}
You could use delegate pattern or closure.
I would do the following
1. I would not use inout pattern, I would first call the popover and then separately update what is needed to be updated
2. In KeyPickerTableViewController define property var actionOnDismiss: (()->())? and setting this action to what we need after initialisation of KeyPickerTableViewController
I could show it in code, but the abstract you've shown is not clear enough to come up with specific amendments. Please refer the illustration below.
import UIKit
class FirstVC: UIViewController {
var key = 0
#IBAction func buttonPressed(_ sender: Any) {
let vc = SecondVC()
vc.action = {
print(self.key)
self.key += 1
print(self.key)
}
present(vc, animated: true, completion: nil)
}
}
class SecondVC: UIViewController {
var action: (()->())?
override func viewDidLoad() {
onDismiss()
}
func onDismiss() {
action?()
}
}
While presenting VC, add dismissing modal VC action in its completion handler, so that Viewcontroller will be presented after dismissal is completed
present(picker, animated: true, completion: { (action) in
//dismissal action
if let delKey = delegatedKey {
key = delKey
}
})