Die iPad-Tastatur wird nicht geschlossen, wenn der modale ViewController-Präsentationsstil UIModalPresentationFormSheet ist


214

Hinweis:

Siehe akzeptierte Antwort (nicht die am besten gewählte) für die Lösung ab iOS 4.3.

Bei dieser Frage handelt es sich um ein Verhalten, das auf der iPad-Tastatur festgestellt wurde und nicht abgelehnt werden kann, wenn sie in einem modalen Dialog mit einem Navigationscontroller angezeigt wird.

Grundsätzlich, wenn ich dem Navigationscontroller die folgende Zeile wie folgt vorstelle:

navigationController.modalPresentationStyle = UIModalPresentationFormSheet;

Die Tastatur wird nicht entlassen. Wenn ich diese Zeile auskommentiere, geht die Tastatur gut weg.

...

Ich habe zwei Textfelder, Benutzername und Passwort. Der Benutzername hat eine Schaltfläche Weiter und das Passwort eine Schaltfläche Fertig. Die Tastatur verschwindet nicht, wenn ich dies in einem modalen Navigationscontroller präsentiere.

WERKE

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
[self.view addSubview:b.view];

FUNKTIONIERT NICHT

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];

Wenn ich den Navigationscontroller-Teil entferne und 'b' als Modal View Controller selbst präsentiere, funktioniert es. Ist der Navigationscontroller das Problem?

WERKE

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
b.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:b animated:YES];
[b release];

WERKE

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
    [[UINavigationController alloc]
         initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

Die folgende SO-Frage scheint das gleiche Problem zu haben, aber es gibt keine Antworten: stackoverflow.com/questions/3019709/…
Kalle

+1 Vielen Dank für Ihre großartige Erklärung. Aber wo muss ich diese Methode hinstellen? Es scheint nicht zu funktionieren, wo ich den Code für die Präsentation der Modellsteuerung erstelle ...
Lorenzo B

1
Es muss in der Modal View Controller-Klasse selbst sein.
Kalle

Vielen Dank. Aha. Ich habe es gelöst, es in eine Kategorie für den UINavigationControllerUnterricht einzuteilen. Prost.
Lorenzo B

Ich bin dir für diese Frage so dankbar. Ich war überrascht, dass resignFirstResponderdas ausgeführt wurde, aber die Tastatur immer noch angezeigt wurde. Mein Szenario (PresentationFormSheet mit Navigationssteuerung) ist genau das gleiche wie Ihres. Danke vielmals!!
sErVerdevIL

Antworten:


115

Überschreiben Sie disablesAutomaticKeyboardDismissalin dem modal dargestellten Ansichts-Controller einfach, um Folgendes zurückzugeben NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

Ja, seit 4.3 scheint dies der Fall zu sein. Wird die Frage aktualisieren. Vielen Dank!
Kalle

2
Dies muss dem Navigations-Controller hinzugefügt werden
Topffleisch

1
Ja, funktioniert, wenn Sie es im NavigationController überschreiben. Das ist das einzige, was für mich tatsächlich funktioniert hat.
James Laurenstin

Lebensretter! Warum macht Apple so etwas? Sicherlich sollte es standardmäßig NO sein und uns erlauben, es zu ändern, wenn wir wirklich wollen
SomaMan

DisablesAutomaticKeyboardDismissal funktioniert nicht mit der von UIViewController abgeleiteten Klasse und wird nie aufgerufen
Jorge Arimany

172

Dies wurde von Apple-Ingenieuren als "funktioniert wie beabsichtigt" eingestuft. Ich habe vor einiger Zeit einen Fehler dafür gemeldet. Ihre Argumentation ist, dass der Benutzer häufig Daten in modaler Form eingibt, um "hilfreich" zu sein und die Tastatur sichtbar zu halten, wo normalerweise verschiedene Übergänge in der modalen Ansicht dazu führen können, dass die Tastatur wiederholt angezeigt / ausgeblendet wird.

Bearbeiten: Hier ist die Antwort eines Apple-Ingenieurs in den Entwicklerforen:

Wurde Ihre Ansicht zufällig mit dem UIModalPresentationFormSheet-Stil präsentiert? Um häufige Ein- und Aus-Animationen zu vermeiden, bleibt die Tastatur manchmal auf dem Bildschirm, auch wenn kein Ersthelfer vorhanden ist. Dies ist kein Fehler.

Dies gibt vielen Menschen Probleme (ich selbst eingeschlossen), aber im Moment scheint es keine Möglichkeit zu geben, es zu umgehen.

AKTUALISIEREN:

In iOS 4.3 und höher können Sie jetzt `-disablesAutomaticKeyboardDismissal 'auf Ihrem View Controller implementieren, um NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

Dies behebt das Problem.


7
Pause Wow, okay. Vielen Dank für das Heads Up. Verdammter Apfel .. :(
Kalle

Haben Sie einen Fehlerbericht an Apple gesendet? Ich habe dies unter der ID # 8384423 getan. Ich habe auch einen Beispielantrag eingereicht, um das Verhalten zu reproduzieren.
Shaggy Frog

3
Ab iOS 4.3 gibt es jetzt eine disablesAutomaticKeyboardDismissal-Methode, die dieses Problem behebt.
Kalle

5
Ich versuche, die MethodeAutomaticKeyboardDismissal zu deaktivieren, aber das Problem wurde immer noch nicht gelöst. Wie kann ich es lösen?
R. Dewi

3
@Snips: Sie müssen eine UINavigationControllerUnterklasse erstellen , die überschrieben wird, disablesAutomaticKeyboardDismissalum sie zurückzugeben, NOund diese als Navigationssteuerung verwenden, wenn Sie ein modales Formularblatt präsentieren. Siehe die Antwort von @ miha-hribar unten.
Pascal

149

Seien Sie vorsichtig, wenn Sie das Modal mit a anzeigen UINavigationController. Sie müssen dann die disablesAutomaticKeyboardDismissalam Navigationscontroller und nicht am Ansichtscontroller einstellen . Sie können dies leicht mit Kategorien tun.

Datei: UINavigationController + KeyboardDismiss.h

#import <Foundation/Foundation.h>

@interface UINavigationController (KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal;

@end

Datei: UINavigationController + KeyboardDismiss.m

#import "UINavigationController+KeyboardDismiss.h"

@implementation UINavigationController(KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal
{
    return NO;
}

@end

Vergessen Sie nicht, die Kategorie in die Datei zu importieren, in die Sie den UINavigationController verwenden.


19
+1, schließlich sehe ich das fehlende Stück von Informationen für dieses Problem hervorgehoben: dass man braucht außer Kraft setzt disablesAutomaticKeyboardDismissalvon UINavigationController, nicht den eigenen View - Controller, um dieses Problem zu beheben.
DarkDust

Nett! Genau das, was ich brauchte. Danke dir.
Justin

Perfekt. Aus offiziellen Dokumenten nicht ersichtlich, aber sinnvoll, da sich der UINavigationController in der Responderkette befindet. Hervorragende Antwort. Danke dir!
Imnk

1
Ich präsentiere einen modalen Dialog von einem UISplitViewController. Ich habe den obigen Code ausprobiert, aber UINavigationController durch UISplitViewController ersetzt, aber es funktioniert immer noch nicht. Sollte diese Methode auch auf einem UISplitViewController funktionieren?
Snips

6
Es ist keine gute Idee, eine doppelte Methode in einer Kategorie zu implementieren. Sie können nie sicher sein, welche Implementierung aufgerufen wird, daher können Sie bestenfalls inkonsistentes Verhalten erwarten. Besser von UINavigationController erben und die Methode in Ihrer benutzerdefinierten Klasse überschreiben.
Sean Woodward

51

Ich habe dieses Problem gelöst, indem ich den UIModalPresentationPageSheetPräsentationsstil verwendet und die Größe sofort nach der Präsentation geändert habe. Wie 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];

Hmmm ... das ist nicht ganz richtig ... das Ändern der Größe bewirkt, dass das Modal lustig malt ... es ist, als würde es den Inhalt zerquetschen, um in die neue Größenbox zu passen oder so ... alles sieht lustig aus. :(
toofah

Es gibt auch Rotationsprobleme mit diesem ... Wenn Sie drehen, während dieses Modal aktiv ist, wird es schrumpfen / wachsen, als wäre es eine vollständige Seitenansicht
toofah

2
toofah, ich habe den Code bearbeitet, um das Problem des Schrumpfens / Wachsens beim Drehen zu lösen. Es geht nur darum, der Übersicht einen flexiblen oberen und unteren Rand zu geben. Ich bin mir nicht sicher, ob ich das andere Verhalten sehe.
Azdev

1
Dies funktioniert nur, solange Sie keine andere Ansicht über diese schieben. Wenn Sie die Ansicht schließen, die über der dargestellten Ansicht von UIModalPresentationPageSheet verschoben wurde, wird die ursprüngliche Größe wiederhergestellt.
V1ru8

Es funktionierte. Aber das Wort in der Ansicht sieht ein wenig verschwommen aus. Ich weiß nicht warum.
Jeswang

1

Wenn Sie eine andere modale Anzeige umschalten, wird die Tastatur möglicherweise ausgeblendet. Es ist nicht schön und es animiert nicht nach unten, aber Sie können es dazu bringen, wegzugehen.

Es wäre großartig, wenn es eine Lösung gäbe, aber im Moment funktioniert dies. Sie können es in einer Kategorie einklemmen UIViewControllerund aufrufen, wenn die Tastatur weg sein soll:

@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

Seien Sie jedoch vorsichtig, wenn Sie viewDidAppear / viewDidDisappear anzeigen und alle diese Methoden aufgerufen werden. Wie ich schon sagte, es ist nicht schön, aber es funktioniert.

-Adam


1

Sie können dies auch in einer universellen App umgehen, indem Sie einfach die Redewendung überprüfen. Wenn es sich um ein iPad handelt, öffnen Sie die Tastatur nicht automatisch und lassen Sie den Benutzer auf das tippen, was er bearbeiten möchte.

Vielleicht nicht die schönste Lösung, aber es ist sehr einfach und benötigt keine ausgefallenen Hacks, die mit der nächsten großen iOS-Version brechen werden :)


1

Fügen Sie diesen Code in Ihre Ansicht ein. WillDisappear: Die Methode des aktuellen Controllers ist eine weitere Möglichkeit, dies zu beheben:

Class UIKeyboardImpl = NSClassFromString(@"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:@selector(activeInstance)];
[activeInstance performSelector:@selector(dismissKeyboard)];

1

Ich fand das disablesAutomaticKeyboardDismissalund das Hinzufügen einer disablesAutomaticKeyboardDismissalFunktion funktionierte bei mir nichtUITextField in einem modalen Dialog .

Die Bildschirmtastatur würde einfach nicht verschwinden.

Meine Lösung war zu , alle Texteingabesteuerelemente in meinem Dialogfeld deaktivieren und die relevanten Steuerelemente einen Bruchteil einer Sekunde später wieder zu aktivieren.

Es scheint , als ob , wenn iOS , dass keiner der sieht UITextFieldKontrollen aktiviert sind, dann ist es nicht loswerden der Tastatur erhalten.


0

Ich bin sicher, Sie haben sich das angesehen, aber Sie sind sicher, dass Ihre Controller-Klasse ordnungsgemäß als UITextField-Delegat angeschlossen ist, oder?


Ich habe es selbst manuell eingestellt und die Delegatenmethoden werden aufgerufen, also ja.
Kalle

0

Vielleicht nicht NEIN zurückgeben, sondern JA. So kann es weggehen.

Und Sie haben auch ein textFieldShouldEndEditingzurückkehrendes JA?

Und warum feuerst du [nextResponder becomeFirstResponder]?! Entschuldigung, ich sehe jetzt

Ich habe auch eine Reihe von UITextViews, deren "bearbeitbare" Eigenschaft auf FALSE gesetzt ist.

Dürfen wir annehmen, dass keiner von ihnen zufällig einen tagWert von hat secondField.tag+1? Wenn ja, sagen Sie ihnen, sie sollen Ersthelfer werden, anstatt den Ersthelfer zurückzutreten. Vielleicht etwas NSLog () in diese if-Struktur einfügen.


1
NEIN = keine Zeilenumbrüche einfügen, soweit ich das beurteilen kann. Und das Setzen auf JA hat es nicht behoben.
Kalle

1
Ein UITextField, das per Definition eine Zeile ist, macht meiner Meinung nach nicht viel mit Zeilenumbrüchen. Es geht also mehr darum, das Drücken der Return / Done-Taste zu verarbeiten, wie in den Dokumenten angegeben.
MVDS

Sind Sie sehr sicher, dass Sie alles richtig angeschlossen haben? Haben Sie NSLog("tf %x / method ...",textField);in alle Delegiertenfunktionen eine eingefügt?
MVDS

Nun, die Delegatenfunktionen werden entsprechend aufgerufen, und sie wären es nicht, wenn der Delegat nicht angemessen eingerichtet wäre. Und der NSLog gibt einen EXC_BAD_ACCESS aus. Warnt mich auch davor, dass es sich um einen inkompatiblen Typ in XCode handelt.
Kalle

D'oh. Entschuldigung, hätte das selbst sehen sollen. Ich habe die Antwort oben mit den Ergebnissen dieser NSLogs aktualisiert, da sich die Formatierung in comm .. selbst ändert.
Kalle

0

Informationen zu Problemen mit UINavigationController finden Sie in meiner Antwort auf eine ähnliche Frage hier: https://stackoverflow.com/a/10507689/321785

Bearbeiten: Ich betrachte dies als eine Verbesserung der Lösung von Miha Hribar (da die Entscheidung dort stattfindet, wo sie stattfinden sollte) und im Gegensatz zu Pascals Kommentar zu einer Kategorie in UIViewController


0

ist vielleicht keine perfekte Lösung, funktioniert aber
[self.view endEditing: YES];
von überall dort, wo Ihre Schaltfläche oder Geste implementiert ist, um Modal zu präsentieren


0
Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.