I am trying to define supported orientations depending on where the user is in my app, I am having a very difficult time doing so.
I have found out thus far that I should use the supportedInterfaceOrientationsForWindow: and shouldAutorotate methods that are now supported in iOS6, however neither method is ever called where I am defining them in my UIViewController.
This is what my code looks like
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientationsForWindow {
return UIInterfaceOrientationMaskPortrait;
}
In my Target Summary Supported Orientatoin I have de-selected all options.. thinking I would just define supported orientation in each of m ViewControllers... I would like to know if this is the correct thing to do?
Now I have read what I am trying to do is dependant on the structue of my app, so Here I will outline my app.
main UIViewController (3 buttons taking you to (3 different navigationControllerViews) Wrong! only one navigationController... sorry its been a long time since I looked at this code.)
secondary UIViewController (holds navigation controller)
other UIViewControllers (appear in secondarys NavigationController)
I would like every ViewController up untill the last one in the NavigationController stack to appear in portrate. The last view in the NavigationController is a special view that needs to be able to rotate its orientation to left or right if needed.
I would like to know if this is possible and if so why isnt the code that I have above working/being called.
Any help would be greatly appreciated.
// Update to question Re:
RootView loads with (three buttons, here is the Method that is called when a button is selected to load the View containing the navigation controller)
- (IBAction)buttonClick: (UIButton *) sender
{
//..
// v ----->
if ([sender isEqual:vUIButton]) {
VSearchViewController *vSearchViewController = [[VSearchViewController alloc] initWithNibName:#"VSearchViewController" bundle:nil];
[self.navigationController pushViewController:vehicalSearchViewController animated:YES];
}
//..
}
Then inside VSearchViewController I load the new views onto the UINavigation stack like this
//..
FModelsViewController *fModelsViewController = [[FModelsViewController alloc] initWithNibName:#"FModelsViewController" bundle:nil];
// Sets the back button for the new view that loads (this overrides the usual parentview name with "Back")
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back" style: UIBarButtonItemStyleBordered target:nil action:nil];
[self.navigationController pushViewController:fModelsViewController animated:YES];
//..
So in review I have set up the navigation controller in the appDelegate and all views in my app are on the navigationStack... I was wrong in saying there are 3 NavigationControllers.. there is only one and every view is added to the stack.. Sorry about that.. Its been a year and a half since I looked at this code..
Are you running the above code on iOS6? Those methods will only be called on iOS6.
Also maybe you could post some code to better illustrate how you are transitioning to these viewControllers so we can get a better understanding of the view hierarchy.
You might want to look at UIViewController's addChildViewController: method.
I think your last view could take advantage of the code written below. It senses the orientation of the device and will show a different view controller for the landscape view (I'm assuming that is what you are trying to do). This means your last view will have a portrait and a landscape option.
#implementation LastViewController
- (void)awakeFromNib
{
isShowingLandscapeView = NO;
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationLastViewChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
- (void)orientationLastViewChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) &&
!isShowingLandscapeView)
{
[self performSegueWithIdentifier:#"LandscapeLastView" sender:self];
isShowingLandscapeView = YES;
}
else if (UIDeviceOrientationIsPortrait(deviceOrientation) &&
isShowingLandscapeView)
{
[self dismissViewControllerAnimated:YES completion:nil];
isShowingLandscapeView = NO;
}
}
on the view controllers leading up to this view that you want locked into portrait, write this code:
- (BOOL)shouldAutorotate {
return NO;
}
as for your supported interface orientations, leave that how you have it.
Related
I am moving with Navigation bar by this method to another location:
- (void)shiftNavigationBar
{
self.navigationController.navigationBar.layer.zPosition = 0;
float currentVersion = 7.0;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion) {
UINavigationBar *navBar = self.navigationController.navigationBar;
[self.navigationController.navigationBar
setFrame:CGRectMake(navBar.frame.origin.x, 92, navBar.frame.size.width, navBar.frame.size.height)];
}
}
I do this in viewDidAppear and when controller is loaded for first time it's okay. But when I click home button and returns to application navigation bar disappear (ok, it didn't disappear I have another bar in place where normally is navigation bar so it "hides" above this bar) and I need to shift navigation bar again but I tried different methods (Will/DidAppear and so) but It's looks that noone is execute when returning from inactive. I know there is method for this in AppDelegate but what method I can use in controller?
Edit:
Methods which I tried but It didn't worked:
1- Add method shiftNavigationBar to AppDelegate and call it in applicationDidBecomeActive
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self shiftNavigationBar];
}
- (void)shiftNavigationBar
{
((UINavigationController*)self.window.rootViewController).navigationBar.layer.zPosition = 0;
float currentVersion = 7.0;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion) {
UINavigationBar *navBar = ((UINavigationController*)self.window.rootViewController).navigationBar;
[((UINavigationController*)self.window.rootViewController).navigationBar
setFrame:CGRectMake(navBar.frame.origin.x, 92, navBar.frame.size.width, navBar.frame.size.height)];
}
}
2- Call controller method from AppDelegate
- (void)applicationDidBecomeActive:(UIApplication *)application
{
UINavigationController *navController = (UINavigationController*)self.window.rootViewController;
[(MAListRepositoriesVC*)navController.topViewController doMyLayoutStuff:self];
}
// I added shiftNavigationBar to method doMyLayoutStuff
3- Observer in controller
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doMyLayoutStuff:) name:UIApplicationDidBecomeActiveNotification object:nil];
Everytime method was called but everytime navigation bar is back at top. It looks like methods are called too soon and after that there are next changes and returns navigation bar back to top.
Edit2:
As right answer I choose answer with replace navigation bar with custom view because that's what I must do. I tried many solutions which I can find but nothing help me. So I created custom view which looks like I need and mainly which is there where I put it.
Can you post a screenshot or mock of the UI?
Probably you should look for a custom view and replace the navigation bar entirely as modifying it is clumsy and will surely break on future updates. Besides it may risk to get your app rejected.
Try this... It's just a temporary fix you said that seems that your methods get called to early when then just delay them a little bit using the method:
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
Just add probs 0.5-1.0 for the seconds, target is obviously self and selector will be #selector(shiftNavigationBar), userInfo nil, and repeats NO.
I'm not to sure about the bar that you mention appears above your desired bar. Do you call that bar using a method? does it load from a nib file? if you can clarify a little bit more I could help you more with this issue. I have an app that uses a custom navigation bar it works just fine but I need a bit more of detail to help you.
Hope this suggestion helps you at least to troubleshoot your issue.
One possibility would be to put the navBar into a different superview, and then to adjust the frame of the new superview. For example, in your navigation controller viewDidLoad (or awakeFromNib, if it's loaded from a Storyboard/XIB):
// Move the current self.view to contentView, create a new self.view,
// and add the contentView to this new view.
self.contentView = self.view; // navBar is a subview of self.view
self.view = [[UIView alloc] initWithFrame:self.contentView.frame];
CGRect contentFrame = CGRectMake(0,92,self.view.frame.size.width, self.view.frame.size.height-92);
self.contentView.frame = contentFrame;
[self.view addSubview:self.contentView];
(You will need to add a new property to the interface: #property (strong, nonatomic) UIView *contentView;). I leave it to you to add in the code for the different device versions.
This seems to survive backgrounding/becoming active, so you don't need code in your AppDelegate.
I have been looking into ways of setting up separate landscape and portrait view controllers to handle a changing orientation. The code posted below is from Apple stating how to do this. I noticed they use performSegueWithIdentifier. It seems odd that a segue is being used.
In order to create a segue on the storyboard I'm assuming I must create a hidden button and drag the connection from the portrait to the landscape view controller. I can then set the segue identifier to "DisplayAlternateView". What is the default segue animation? Or is the default to turn the animation off?
Also why is this code in the awakeFromNib method? Shouldn't it be in viewDidLoad? Is awakeFromNib called before viewDidLoad?
Also I'm assuming I must have a different target action for every scene of my storyboard. If I have portrait view A, B and C with a corresponding landscape view A, B and C, should I have the following changes to the Apple code
on my A view:
selector:#selector(orientationChangedA:)
then on my B
selector:#selector(orientationChangedB:)
then on my C
selector:#selector(orientationChangedC:)
This way each method can perform it's own segue.
I feel like I might be over complicating things here. Are the separate segues causing me to do extra work or is this how how orientation switching to separate view controllers normally handled?
Here is the code from Apple saying how to handle orientation changes with different view controllers:
#implementation PortraitViewController
- (void)awakeFromNib
{
isShowingLandscapeView = NO;
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
- (void)orientationChanged:(NSNotification *)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if (UIDeviceOrientationIsLandscape(deviceOrientation) &&
!isShowingLandscapeView)
{
[self performSegueWithIdentifier:#"DisplayAlternateView" sender:self];
isShowingLandscapeView = YES;
}
else if (UIDeviceOrientationIsPortrait(deviceOrientation) &&
isShowingLandscapeView)
{
[self dismissViewControllerAnimated:YES completion:nil];
isShowingLandscapeView = NO;
}
}
Here is the thing, I have to integrate an augmented reality functionality into an app. After testing it aside, now I'm ready to integrate it. The app always runs in Portrait, I decided to show the augmented reality when rotating the iPhone in Landscape Right or Left (and of course, if I go back in Portrait the original view controller is shown). In fact the augmented reality is presented modally.
I've got viewController calling ARViewController (modally). It works fine if I rotate like 2 or 3 times, but then this ARViewController is not called anymore, but the app is still running, no crash, no freeze. This ARViewController is initialised with ARController, a class computing all needed for the augmented reality. If I call this ARViewcontroller without the ARController, switching between the view controllers works very fine, a blank window will be called but at least I can rotate the device as much as I want. So, this must come from the ARController, I documented myself on memory leaks (by the way I'm using ARC), I think this could be the reason to the issue since I'm using this ARController many times.
But before going further, I'd like to know if I'm doing anything wrong that could influence the ARController by switching between view controllers:
Here is how I call the ARViewController in viewController:
if (orientation == UIDeviceOrientationLandscapeLeft) {
NSLog(#"ViewController Landscape left");
ARViewController *arVC = [[ARViewController alloc] initWithNibName:#"ARViewController" bundle:nil];
[self setCameraViewController:arVC];
[arVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal];
[[self navigationController] presentModalViewController:cameraViewController animated:YES];
arVC = nil;
}
else if (orientation == UIDeviceOrientationLandscapeRight) {
NSLog(#"ViewController Landscape Right");
ARViewController *arVC = [[ARViewController alloc] initWithNibName:#"ARViewController" bundle:nil];
[self setCameraViewController:arVC];
[arVC setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal];
[[self navigationController] presentModalViewController:cameraViewController animated:YES];
arVC = nil;
}
the initialisation of ARViewController:
- (void)viewDidLoad {
[super viewDidLoad];
self.arController = [[ARController alloc] initWithViewController:self];
arController.filterDiscover = filterDiscover;
arController.filterEat = filterEat;
arController.filterSleep = filterSleep;
// Listen for changes in device orientation
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange:) name: UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
//if ViewController presents this modal ARViewController
if(!arController.filterDiscover && !arController.filterEat && !arController.filterSleep)
[arController callAlertViewToFilter];
else
[arController loadData];
}
And finally here is how I go back to the original view controller if I rotate to Portrait in ARViewController:
if (orientation == UIDeviceOrientationPortrait){
NSLog(#"ARViewController Portrait");
[self setArController:nil];
[[super presentingViewController] dismissModalViewControllerAnimated:YES];
}
I tried to be as clear as possible, if anyone has ever had an issue similar to this, it could be great have some clues to solve this. I could have shown the code of the ARController but it is a little too long, for now I'd just like to know if there is anything wrong here. If needed I'll show it.
This might help, I found this output in the debug area when the ARViewController is not being displayed anymore:
2012-10-24 17:57:51.072 beiceland[20348:907] ViewController Landscape Right
2012-10-24 17:57:51.073 beiceland[20348:907] Warning: Attempt to present <ARViewController: 0x203f0c60> on <RevealController: 0x1cd5dca0> while a presentation is in progress!
My bad I was way out of the solution here.
I used the debugger and breakpoints and repeated the critical sequence, I found out I was not entering:
- (void)deviceOrientationDidChange:(NSNotification *)notification
anymore. So this is the first time I see such things, the listener for device orientation changes suddenly stops firing. Consequently my solution is quite brutal but at least it has the merit of stopping the issue, just after detecting the device orientation change I stop the listener:
if (orientation == UIDeviceOrientationLandscapeLeft) {
NSLog(#"ViewController Landscape left");
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
ARViewController *arVC = [[ARViewController alloc] initWithNibName:#"ARViewController" bundle:nil];
[self setCameraViewController:arVC];
arVC = nil;
[cameraViewController setModalTransitionStyle: UIModalTransitionStyleFlipHorizontal];
[[super navigationController] presentModalViewController:cameraViewController animated:YES];
}
And each time I'm using the viewController (the calling view controller), I reinitialize the listener, it means in viewDidAppear:
// Listen for changes in device orientation
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange:) name: UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
Well now it's solved but I have to admit I'm disappointed of finding such kind of solution.
Well, I never used ARC before, but according to what I see, you initialize a ARViewController everytime you change orientation ( on landscape ). Why not instantiating 2 ARViewController for good, and calling them everytime ?
Except if you are sure that these are released everytime you switch to portrait.
Plus, why don't you just use pushViewController:animated: ?
And one last thing, you presentModalViewController to you navigationController, but you dismiss it in [super presentingViewController], maybe you could add this one ?
I have an app that is loading a overlay controller (shows camera so I can scan). It works great on the iPhone and it works great on the iPad after I call it a second time. Let me explain.
I have a UIButtonBarItem that loads a view controller modally. There are several controls on in the controller, most buttons (defined using a nib). If I load the controller (by responding to the UIButtonBarItem action) on an iPhone, it loads and all the buttons work fine, every time.
But... if I load the same view controller using an UIPopoverController, none of the buttons will respond the first time I load it. So, I touch the screen somewhere outside of the controller and dismiss the controller. Then, I touch the same action button again and now when the controller loads, all the controls in the the view controller work great. REALLY WEIRD!
[POSSIBLE HINT]
The buttons were placed all over the place in weird positions when I loaded it the first time. Each subsequent call had the buttons showing in the right places. I got this to work by disabling "Autoresize subviews" in the nib. The buttons are now in the right places but they still won't respond when I load this popover the first time.
Here's the code I'm using to respond to the UIButtonBarItem.
-(void)launchOverlayController:(id)sender
{
if([pickerControllerPopover isPopoverVisible])
{
[pickerControllerPopover dismissPopoverAnimated:YES];
pickerControllerPopover = nil;
return;
}
// Deselect any selected cell
[self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:NO];
// Working code that shows the overlay (camera on) but the overlay takes the whole screen
SRSScanVINViewController *scanVINViewController = [[SRSScanVINViewController alloc] init];
[pickerController setOverlay:scanVINViewController];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:scanVINViewController];
[navController setModalPresentationStyle:UIModalPresentationFormSheet];
[navController setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
pickerControllerPopover = [[UIPopoverController alloc] initWithContentViewController:pickerController];
[pickerControllerPopover setDelegate:self];
[pickerControllerPopover setPopoverContentSize:CGSizeMake(320.0f, 460.0f)];
[pickerControllerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else
{
[self presentViewController:pickerController animated:YES completion:nil];
}
}
I'm totally out of ideas. I can't see why the controls within the overlaycontroller would work fine every time I call it except for the first time.
Thanks for anyones help in advance.
So the answer is that the superclass is mucking with your view. I'm going to guess it was not designed to be subclassed, but no way to know for sure. What it does in one of the 'view..' methods is to override self.view with its own view, and make your view a subview of that view. The first time around it makes the frame of your view have zero dimensions. The next time it leaves it as it was before - maybe some persistent flag. It also inserts the view at different places in its subviews, which seems odd but if you have the code you'd probably see why.
Soooo - the solution to the problem is to just move your view's subviews to the superView (the subclass's view), then set your view's frame to the null frame:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated]; // StackOverflow says to add this TCL?
// Set the initial scan orientation
[self setLayoutOrientation:self.parentPicker.orientation];
if ([self.parentPicker hasFlash])
{
[flashButton setEnabled:YES];
[flashButton setStyle:UIBarButtonItemStyleBordered];
[self.parentPicker turnFlash:NO];
} else
{
[flashButton setEnabled:NO];
}
textCue.text = #"";
viewHasAppeared = NO;
// move the subviews
while([self.view.subviews count]) [self.view.superview addSubview:[self.view.subviews objectAtIndex:0]];
self.view.frame = CGRectMake(0,0,0,0);
}
PS: note that you were missing a superView call here but it didn't seem to matter much (you don't know which method your complex superclass may want so I'd be sure to send them everything you intercept.
Note:
See accepted answer (not top voted one) for solution as of iOS 4.3.
This question is about a behavior discovered in the iPad keyboard, where it refuses to be dismissed if shown in a modal dialog with a navigation controller.
Basically, if I present the navigation controller with the following line as below:
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
The keyboard refuses to be dismissed. If I comment out this line, the keyboard goes away fine.
...
I've got two textFields, username and password; username has a Next button and password has a Done button. The keyboard won't go away if I present this in a modal navigation controller.
WORKS
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
[self.view addSubview:b.view];
DOES NOT WORK
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
UINavigationController *navigationController =
[[UINavigationController alloc]
initWithRootViewController:b];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
navigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];
If I remove the navigation controller part and present 'b' as a modal view controller by itself, it works. Is the navigation controller the problem?
WORKS
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
b.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:b animated:YES];
[b release];
WORKS
broken *b = [[broken alloc] initWithNibName:#"broken" bundle:nil];
UINavigationController *navigationController =
[[UINavigationController alloc]
initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];
This has been classified as "works as intended" by Apple engineers. I filed a bug for this a while back. Their reasoning is that the user is often going to be entering data in a modal form so they are trying to be "helpful" and keep the keyboard visible where ordinarily various transitions within the modal view can cause the keyboard to show/hide repeatedly.
edit: here is the response of an Apple engineer on the developer forums:
Was your view by any chance presented with the UIModalPresentationFormSheet style? To avoid frequent in-and-out animations, the keyboard will sometimes remain on-screen even when there is no first responder. This is not a bug.
This is giving a lot of people problems (myself included) but at the moment there doesn't seem to be a way to work around it.
UPDATE:
In iOS 4.3 and later, you can now implement `-disablesAutomaticKeyboardDismissal' on your view controller to return NO:
- (BOOL)disablesAutomaticKeyboardDismissal {
return NO;
}
This fixes the issue.
Be careful if you are displaying the modal with a UINavigationController. You then have to set the disablesAutomaticKeyboardDismissal on the navigation controller and not on the view controller. You can easily do this with categories.
File: UINavigationController+KeyboardDismiss.h
#import <Foundation/Foundation.h>
#interface UINavigationController (KeyboardDismiss)
- (BOOL)disablesAutomaticKeyboardDismissal;
#end
File: UINavigationController+KeyboardDismiss.m
#import "UINavigationController+KeyboardDismiss.h"
#implementation UINavigationController(KeyboardDismiss)
- (BOOL)disablesAutomaticKeyboardDismissal
{
return NO;
}
#end
Do not forget to import the category in the file where you use the
UINavigationController.
In the view controller that is presented modally, just override disablesAutomaticKeyboardDismissal to return NO:
- (BOOL)disablesAutomaticKeyboardDismissal {
return NO;
}
I solved this by using the UIModalPresentationPageSheet presentation style and resizing it immediately after I present it. Like so:
viewController.modalPresentationStyle = UIModalPresentationPageSheet;
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
viewController.view.superview.autoresizingMask =
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin;
viewController.view.superview.frame = CGRectMake(
viewController.view.superview.frame.origin.x,
viewController.view.superview.frame.origin.y,
540.0f,
529.0f
);
viewController.view.superview.center = self.view.center;
[viewController release];
If you toggle a different modal display you can get the keyboard to disappear. It's not pretty and it doesn't animate down, but you can get it to go away.
It'd be great if there was a fix, but for now this works. You can wedge it in a category on UIViewController and call it when you want the keyboard gone:
#interface _TempUIVC : UIViewController
#end
#implementation _TempUIVC
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#end
#implementation UIViewController (Helpers)
- (void)_dismissModalViewController {
[self dismissModalViewControllerAnimated:NO];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
[self release];
}
- (void)forceKeyboardDismissUsingModalToggle:(BOOL)animated {
[self retain];
_TempUIVC *tuivc = [[_TempUIVC alloc] init];
tuivc.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:tuivc animated:animated];
if (animated) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_dismissModalViewController) name:UIKeyboardDidHideNotification object:nil];
} else
[self _dismissModalViewController];
[tuivc release];
}
#end
Be careful with this though as you viewDidAppear / viewDidDisappear and all those methods get called. Like I said, it's not pretty, but does work.
-Adam
You could also work around this in a universal app by simply checking the idiom and if it's an iPad, don't pop up the keyboard automatically at all and let the user tap whatever they want to edit.
May not be the nicest solution but it's very straightforward and doesn't need any fancy hacks that will break with the next major iOS release :)
Put this code in your viewWillDisappear: method of current controller is another way to fix this:
Class UIKeyboardImpl = NSClassFromString(#"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:#selector(activeInstance)];
[activeInstance performSelector:#selector(dismissKeyboard)];
I found that disablesAutomaticKeyboardDismissal and adding a disablesAutomaticKeyboardDismissal function didn't work for my UITextField in a modal dialog.
The onscreen keyboard just wouldn't go away.
My solution was to disable all text-input controls in my dialog, then re-enable the relevant ones a fraction of a second later.
It seems as though when iOS sees that none of the UITextField controls are enabled, then it does get rid of the keyboard.
I'm sure you have looked at this, but you are sure that your controller class is properly hooked up as the UITextField delegate, right?
maybe don't return NO, but YES. So it can go away.
And you have a textFieldShouldEndEditing returning YES as well?
And why are you firing [nextResponder becomeFirstResponder]?! sorry i see now
I also have a number of UITextViews
which all have their "editable"
property set to FALSE.
May we assume none of them, by any chance, has a tag value of secondField.tag+1? If so, you're telling them to become first responder, instead of resigning the first responder. Maybe put some NSLog() in that if structure.
For those having trouble with UINavigationController, see my answer to a similar question here:
https://stackoverflow.com/a/10507689/321785
Edit:
I consider this an improvement to Miha Hribar's solution (since the decision is taking place where it should), and as opposed to Pascal's comment regarding a category on UIViewController
may be not a perfect solution ,but works
[self.view endEditing:YES];
from wherever your button or gesture is implemented to present modal
Swift 4.1:
extension UINavigationController {
override open var disablesAutomaticKeyboardDismissal: Bool {
return false
}
}