How to programmatically tap Tabbar item (not selectedIndex) - ios

here is resume of my app:
I have tab bar. When user tap on the tabbar item
appropriate view controller is presented by "slide-to-side"
animation (like in iP homescreen).
Code is in method tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool.
I have alert. When user tap on button, I want to direct him to the specific tab. But when I use self.selectedIndex = #, VC is showen, but without animation. Is there any way to achieve same action like tap on item? Thank you

Programmatically selecting the tab doesn't trigger any delegate methods. This is true of any control. Since you explicitly chose to do something, you already know you did it. You don't need a delegate method to tell you. This is by design and it is a good thing.
There is a simple solution. Put whatever animation code is inside the delegate method into its own method. Then call that method from the delegate method. Now you can also call that new method when you call self.selectedIndex = #.

Related

How to detect back button is pressed in the next viewController in a navigationController

I want to detect if back button is pressed in the next viewController in a navigationController.
Let's say I have VC_A and VC_B viewControllers in a navigationController. I know how to detect if back button is pressed in a current view controller but I do not know how to detect it in a previous viewController.
Edit:
I go from VC_A to VC_B and when I press back button in VC_B then I want to call a function in VC_A.
You could use notification center. This link has a nice tutorial: https://learnappmaking.com/notification-center-how-to-swift/
I want to detect if back button is pressed in the next viewController in a navigationController.
I'm not sure I understand this exactly, but it really doesn't matter much: in essence, you're talking about some view controller (call it controllerA), whose views aren't currently visible, finding out about a change that affects some other view controller (controllerB). The usual reason for needing such a thing is so that controllerA can update some data that it manages.
A better way to handle that is to have both controllers share a common data model. Any application state that's affected by something like a view controller being dismissed is shared data that should be part of the data model. controllerA really shouldn't care about whether controllerB's back button was tapped or not... that event is only the business of controllerB (and arguably the navigation controller that manages it). What controllerA should care about is updating its own views according to whatever changes happened while it was off screen, and those changes should be recorded in the model by controllerB and any other view controllers that might have been active along the way.
I'm suggesting you to do that with Notification Center like AglaiaZ suggested you. But if you're not feeling comfortable with using Notification Center, then try this more basic solution with viewWillAppear delegate method in viewController from which you're tracking are you back from B VC. So, let's go.
Set this variable in your current view controller class where you want to trigger method when the back button is pressed on the specific view controller, let's call that specific view controller B VC.
let isFromBViewController = false
Then in code block where you're triggering the transition to B VC set this variable to true.
func goToBViewController() { // This method is triggering transition from A VC to B VC
isFromBViewController = true }
And then in viewWillAppear delegate method check did current VC from which we triggered the transition to B VC have appeard from B VC.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if isFromBViewController {
// code for doing something when you got back from B VC
isFromBViewController = false
}}
And that's it.
But, again I'm suggesting you to use the notification center as #AglaiaZ suggested, the tutorial is easy, and with that tutorial I've also learned how to use Notification Center and how to create and use custom notifications.
Good luck.
If I understood correctly, you want to do something when the back button in the navigation bar at the current view controller is pressed, and the user is going back from the current B view controller to A view controller.
Put this line of code in the view controller in which you want to track when the user has pressed the back button.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isMovingToParent {
//your code when back button is pressed
}
}

Call delegate when user tap "Back" button

I need a way to change text depending of user input, when user tap back button. I followed that solution: Find out if user pressed the back button in uinavigationcontroller?
and did add following code in viewDidLoad:
if ([self isMovingFromParentViewController]) {
NSLog(#"isMoved");
[self.delegate stringChangedTo:self.myTextField.text atIndex:self.indexToPass];
}
However, nothing changed. More to say, method is not called (NSLog dont output a string).
How could i find a way to call delegate when user tap back button?
That code needs to be in viewWillDisappear: or viewDidDisappear:. not viewDidLoad.
viewDidLoad is called when the view controller's view is loaded. You want to call the delegate when the view controller is being dismissed.
There is also a UINavigationControllerDelegate protocol. You can get notified when a given view controller is shown by implementing either of these:
-navigationController:willShowViewController:animated:
-navigationController:didShowViewController:animated:
ADDENDUM:
In my opinion, using the delegate is a cleaner design, because you get notified precisely when a navigation event occurs. View controller life cycle methods such as -viewDidDisappear:, etc. can get called when you present/dismiss a modal view controller, and require that you add logic to discern those.

Tab bar, tap to Root View Controller

I have a Swift project.
It has a UINavigationViewController inside a UITabBarController. When tapping the tab responsible for showing the Navigation View Controller twice, it jumps back to the root view controller of the Nav.
How can I disable this using swift?
NB. I've seen Objective C implementations using the UITabBarControllerDelegate but I don't think I'm doing the right thing in Swift.
Thanks.
Swift 3.0
add UITabBarControllerDelegate to master class
override func viewDidLoad() {
tabBarController?.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
_ = navigationController?.popToRootViewController(animated: true)
}
The proper way to achieve it is to use the tabBarController:shouldSelectViewController: method of the UITabBarControllerDelegate protocol. The problem I could see here is that you are not sure where to set the delegate. There must be no big difference between doing in Objective C or Swift.
Here are a few simple steps you may need to try:
Retrieve the tab bar controller:
I don't know your app's UI structure, but you should be able to get the tab bar controller easily from code. It could be a property if you created it programmatically, or merely the key window's rootViewController if you drag & drop it to the main storybard.
Assign the tab bar controller's delegate to an instance of any class you want as long as the class conform to the UITabBarControllerDelegate protocol.
Implement the tabBarController:shouldSelectViewController: method mentioned above to decide what should be shown when a tab is selected.
If you can provide some code, I can also show you how you can make it by example.
Good luck.

iOS Swift Push Segue Catch Trigger Back Button Function

What function gets triggered when a user hits the back button on a push page? I need to set some properties before going back to the previous page. ViewWillDisapper is not what I'm looking for
You will want to use either viewWillDisappear or viewDidDisappear to monitor a user going back on a pushed page (assuming you mean this is inside a navigation controller).
Just like when you call your instance method of UINavigationController to "pushViewController:(BOOL)animated:" guess what method is called to POP a view controller? try something like
[self.navigationBar.backButton //Not sure if this is what its called addTarget:self selector:#selector(popViewController)]
and fill in the rest of the method with UIEventTouchUpInside so when the user presses the back button on navigation bar it will jump into you're overrided function.
Make your View inherit UINavigationController protocols and then overide popViewController method.
I suggest looking at UINavigationController class reference if that didn't answer your question.

Return values to presenting view controller when navigation back button pressed

I'm having trouble piecing this all together. I have a view controller that opens up another (pushes it on to the navigation stack). On that presented view controller, the user enters a value in a text view. When the user pushes the back button in the navigation, I want to be able to pass the value that they entered in the text view back to the presenting controller.
I've looked for a way to use unwind segue with the back button but haven't found anything. When I create my back button (programmatically) I use initWithTitle:style:target:action but I'm not sure how in implementing the action method that I'll be able to access the value set in the presented controller. Might have to use a delegate to link the two, but not sure of the exact integration point for this scenario.
I feel like I'm so close here and a little help would get me there. Thanks!
The two most common models to use for this interaction are for the child view controller to have either a delegate or a completion block. Either would be set in the prepareForSegue method. My personal preference is the completion block method just because it keeps code contained, but ymmv.
There are also multiple models for detecting when your child view controller is dismissed and you need to invoke the delegate and/or completion:
Use a custom back button. Not a fan of this as it can be an issue to create a back button that really looks and acts like the Apple original, especially if supporting iOS 6 and iOS 7.
Hook viewDidDisappear and see if you're still in the navigation controller's viewControllers array. This is better as the back button works right, but it still feels kind of hokey.
Use the UINavigationBarDelegate method navigationBar:shouldPopItem: This is attractive, especially if you have other validation that needs to happen like checking for saved/unsaved values. To implement this you'll have to subclass UINavigationController and forward the method to your child view controller.
EDIT: Details on Option 2:
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if(![self.navigationController.viewControllers containsObject:self])
{
// We're not still in the navigation stack so we must've been
// popped. If we were pushed, viewDidDisappear would be called
// but viewControllers containsObject:self would be true
}
}
EDIT: Clarified Option 3: in your navigation controller subclass
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
UIViewController* top = self.topViewController;
if([top respondsToSelector:#selector(navigationBar:shouldPopItem:)])
return [(id)top navigationBar:navigationBar shouldPopItem:item];
return [super navigationBar:navigationBar shouldPopItem:item];
}
Then you can implement navigationBar:shouldPopItem: in the classes that need the functionality.
the back button does not actually comes up with any event associated with itself so that you can pass the values between the previous and to be Popped ViewController.
You would have to implement Delegate pattern to pass values. In this case as you cant catch when backButton is pressed, you need to use custom leftBarButtonItem or use a image with < in itself.

Resources