I am presenting modal using the following code :
AddName *add = [[AddName alloc] initWithNibName:#"AddName" bundle:nil]
add.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalView:add animated:YES];
And After my work I use following code to go back on my main view.
[self dismissModalViewControllerAnimated:YES];
So it use to call -viewWillAppear by default.
My problem is that,
It was working fine with iOS4.3.
But Its not working with iOS5.
What should I do ? Or Is that any bug in iOS5?
-viewWillAppear is only guaranteed to be called in places where the -viewWillDisappear has also been called. For most modal windows on the iPad, this is not the case, since they don't obscure the entire page.
The solution to your problem will depend on what you need the -viewWillAppear for, but in general, you're likely to need to make a call directly from the same place that you dismiss the modal view controller.
One common mechanism for this, especially in cases where you might use that same modal view somewhere else, is to give the modal view controller a delegate which is called when the view is about to disappear. This will give you a chance to take the responses from the modal window, or even just force a data reload in the delegate view.
Hope this helps.
iOS 5 definitely changed their calls to viewWillAppear and viewWillDisappear. For instance, subviews (View Controller's views as subviews to be exact) in a UIScrollView, viewWillDisappear will get called when you push another view controller onto the stack. However, when the view controller is popped, viewWillAppear does not get called. These methods were never called in iOS 4 on UIScrollView subviews.
This is strange behavior to me. Couple that with the fact that regardless of what should happen, if you could rely on it happening in iOS 4, it should not be working differently in iOS 5. Most of the time, I have no idea in which particular instance each one is called, I usually trial and error it as I'm in the zone coding. If it works the way I like, I move on. Then iOS 5 comes in and throws a wrecking ball into everything.
I have also experienced when a UINavigationController's view is a subview, and a ViewController is pushed on the navigation controller stack, viewWillAppear never gets called in iOS 4, but does get called in iOS 5. Go figure.
I had the same problem.
I found that viewWillAppear isn't get called after dismissing modal but viewDidAppear is. So just try viewDidAppear instead.
Related
I have code in the viewWillAppear method to run before the screen will be displayed again. This works fine if I call popToRootViewController, and then the view is brought up again. But if one presses the back button and popViewController is called, the viewWillAppear never gets called.
Is there a method that gets called when the view appears from popViewController being called?
Normally, viewWillAppear is called when the Back button is hit. You might try a Clean in Xcode and reset your simulator; sometimes that can lead to problems like this. If you have a complex modal view structure, there are apparently cases where viewWillAppear is NOT called. You can use UINavigationControllerDelegate willShowViewController method to call ViewWillAppear; see a complete answer and solution here:
When using a UINavigationController the viewWillAppear or viewDidAppear methods of my controller are not called
I had tried presenting a UIPopoverController on a viewWillAppear on a view presented via a modal view controller. However when doing so the UIPopoverController immediately got dismissed. Any idea why this might have happened and the right way to do so?
Don't do any view handling in -viewWillAppear, because there is no guarantee that the view has loaded. Move all implementations into -viewDidAppear for safer execution.
I have a tabBar controller. Tapping the active tab, by default, calls popToRootViewController on that tab's navigation controller. That is what I want, but I also need to do some customization when this happens. The view controller in question has a nav controller, but is not a subclass of UINavigationController. How can I listen for when popToRootViewController occurs and take some action?
You can use UINavigationControllerDelegate's method:
– navigationController:didShowViewController:animated:
and check if the shown controller is the controller you want.
Hopes this helps
(I remember using this in iOS 2.x and it was a little bit buggy, I wonder if is ok now. It should be since it's 4 already)
You can put you code inside the method – tabBarController:didSelectViewController: of the UITabBarController delegate, or maybe inside the UIViewController's - viewWillAppear:animated: method.
Note:
If you have added your Tabbarcontroller in the navigation stack,
-(void)viewWillAppear:(BOOL)animated
would not be called in iOS 4.2 or below, I wasted so many days to figure out this.
Trying to fix a very strange error, i have 3 view controllers that start from the app delegate and push each other accordingly. The 3rd view controller then has a toolbar button that calls the code here:
-(void)showEventBrowser;
{
accelManeger.delegate = nil;
NSLog(#"%u",[self.navigationController.viewControllers count]);
[self.navigationController popToRootViewControllerAnimated:NO];
}
This works the first time round but when i come back to this view controller and try again. Firstly it reports that there are 3 view controllers on the stack. It then deallocs the 2nd view controller in the stack and doesnt crash but will not go any further. If i hit the button again it says there are no view controllers on the stack and fails to respond.
I have logs for all the viewdid, viewwill, e.t.c in each view controller and there appears to be no odd behaviour. Also no memory warnings from any view controllers.
Why would this work once through but not the second time ?
Well i Fixed this.
I was trying to poptorootviewcontroller from a viewcontroller that had no view but isntead just displayed a UIImagepickercontroller. Even when attempting to dissmiss this modalviewcontroller first, (even with a delay), i still had the same problem. I instead changed the viewcontroller in question to a UIMagepickercontroller subclass and handle the present and dismiss in another viewcontroller.
Lesson learnt, dont pop to root with UIImagepickercontroller modal view ontop.
I'm looking for a way to slide the keyboard into view from the right, like what happens in the Contacts application when you edit a note.
My problem is that when I call [someTextView becomeFirstResponder] in viewWillAppear, the keyboard immediatly pops up with no animation. And when I call it in viewDidAppear, the view first slides in from the right (UINavigationController does the sliding), and then the keyboard slides in from the bottom.
Is it possible to have the keyboard slide in from the right, together with the view?
Solution
In iOS 7, calling becomeFirstResponder on _textView in viewDidLayoutSubviews works.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[_textView becomeFirstResponder];
}
Note: Doing it in viewWillLayoutSubviews also works.
Explanation
Read the discussion in the docs for becomeFirstResponder.
You may call this method to make a responder object such as a view the first responder. However, you should only call it on that view if it is part of a view hierarchy. If the view’s window property holds a UIWindow object, it has been installed in a view hierarchy; if it returns nil, the view is detached from any hierarchy.
When using a navigation controller to push your custom view controller onscreen, self.view.window is still nil by the time either viewDidLoad or viewWillAppear: is called. So, _textView.window is also nil in the same methods, since _textView is a subview of self.view, i.e., they're both in the same window. No matter how you present your custom view controller, self.view.window (and thus _textView.window) is also nil in initWithNibName:bundle:. self.view.window is set by the time viewDidAppear: is called, but that's too late because by that time, the navigation controller has already completed the animation of pushing the view onscreen.
self.view.window is also set by the time either viewWillLayoutSubviews or viewDidLayoutSubviews is called and these methods are called before the push animation of the navigation controller begins. So, that's why it works when you do it in either of those methods.
Unfortunately, viewWillLayoutSubviews and viewDidLayoutSubviews get called a lot more than just on the initial navigation controller push. But, navigationController:willShowViewController: and willMoveToParentViewController: get called too soon (after viewDidLoad but before self.view.window is set) and navigationController:didShowViewController: and didMoveToParentViewController: get called too late (after the push animation).
The only other way I can think of doing it is to somehow observe the window property of _textView so that you get notified when it changes, but I'm not sure how to do that since window is readonly.
All you need to do is tell the text view in question to become the first responder in the viewDidLoad method of the view controller you're pushing onto the navigation stack:
override func viewDidLoad() {
super.viewDidLoad()
someTextView.becomeFirstResponder()
}
This works in iOS 8. The keyboard slides in from the right along with the view.
In iOS 7 (or any version before) you can make a simple thing in loadView, viewDidLoad or viewWillAppear
[yourTextView performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
In this case you will get left-to-right appearance of the keyboard aligned with the motion of pushing view controller.
For iOS 7 I've found the following solution to work the best for me:
-Import UIResponder-KeyboardCache to your project.
-Add [UIResponder cacheKeyboard:YES]; to the viewDidLoad of the view before the keyboard view. It might be better to do this immediately when the application loads or during a time convenient when you can afford it (during an HTTP request, for example). In most cases, simply in the view before is sufficient.
-Add the following to the viewDidLoad of the keyboard view.
dispatch_async(dispatch_get_main_queue(), ^{
[_textField becomeFirstResponder];
});
To explain, this will preload the keyboard view, which will remove the delay from the first call of the keyboard view. Calling becomeFirstResponder on the text field in the main queue causes it to slide in with the view instead of animating upward before the view slides in.
You could try sending the becomeFirstResponder message to the new view controller before you push it onto the stack. For example:
-(void)functionWhereYouPushTheNewViewController {
yourNewViewController *newVC = [[yourNewViewController alloc] init];
[newVC.yourTextView becomeFirstResponder];
[self.navigationController pushViewController:newVC animated:YES];
}
I have found that changing animations on things like they keyboard is pretty tough though, and if you read the Human Interface Guidelines Apple makes it pretty clear that they want certain things to act in certain ways, all the time. There are ways to change the behaviors of certain animations but they often involve undocumented API calls and are grounds for rejection from the app store. It would be a violation of HIG to have pushed views slide up from the bottom, for example.
Hope this helps.