Klawiatura iPada nie zostanie odrzucona, jeśli modalnym stylem prezentacji ViewController jest UIModalPresentationFormSheet

214

Uwaga:

Zobacz zaakceptowaną odpowiedź (nie wybraną najlepiej) dla rozwiązania z iOS 4.3.

To pytanie dotyczy zachowania wykrytego na klawiaturze iPada, gdzie odmawia odrzucenia, jeśli jest pokazane w modalnym oknie dialogowym z kontrolerem nawigacyjnym.

Zasadniczo, jeśli przedstawię kontrolerowi nawigacji następujący wiersz:

navigationController.modalPresentationStyle = UIModalPresentationFormSheet;

Klawiatura odmawia zwolnienia. Jeśli skomentuję ten wiersz, klawiatura zniknie.

...

Mam dwa pola tekstowe, nazwę użytkownika i hasło; nazwa użytkownika ma przycisk Dalej, a hasło ma przycisk Gotowe. Klawiatura nie zniknie, jeśli przedstawię to w modalnym kontrolerze nawigacyjnym.

PRACUJE

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

NIE DZIAŁA

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

Jeśli usunę część kontrolera nawigacji i sam przedstawię „b” jako kontroler widoku modalnego, to zadziała. Czy problem stanowi kontroler nawigacji?

PRACUJE

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

PRACUJE

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
    [[UINavigationController alloc]
         initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];
Kalle
źródło
Następujące pytanie SO wydaje się mieć ten sam problem, ale nie ma odpowiedzi: stackoverflow.com/questions/3019709/…
Kalle
+1 Dziękujemy za wspaniałe wyjaśnienie. Ale gdzie muszę umieścić tę metodę? Wydaje się, że nie działa, gdy tworzę kod do prezentacji kontrolera modelu ...
Lorenzo B
1
Musi należeć do samej klasy kontrolera widoku modalnego.
Kalle
Dzięki. Widzę. Rozwiązałem umieszczenie go w kategorii dla UINavigationControllerklasy. Twoje zdrowie.
Lorenzo B
Jestem ci bardzo wdzięczny za to pytanie. Byłem zaskoczony, że resignFirstResponderto działa, ale klawiatura wciąż jest wyświetlana. Mój scenariusz (PresentFormSheet with navig contrllr) jest dokładnie taki sam jak twój. Wielkie dzięki !!
sErVerdevIL

Odpowiedzi:

115

W kontrolerze widoku, który jest prezentowany modalnie, po prostu przesłoń, disablesAutomaticKeyboardDismissalaby zwrócić NO:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}
Sebastian H.
źródło
Tak, od 4.3 wydaje się, że tak jest. Zaktualizuje pytanie. Dzięki!
Kalle
2
To należy dodać do kontrolera nawigacyjnego
pottedmeat
1
Tak, działa, gdy zastąpisz go w Nawigatorze nawigacji. To jedyna rzecz, która naprawdę dla mnie zadziałała.
James Laurenstin,
Oszczędzanie życia! Dlaczego Apple robi takie rzeczy? Na pewno powinno być domyślnie NIE i pozwolić nam to zmienić, jeśli naprawdę chcemy
SomaMan
Nie działa na klasie pochodnej UIViewController, wyłączaAutomaticKeyboardDismissal nigdy nie jest wywoływany
Jorge Arimany
172

Zostało to sklasyfikowane przez inżynierów Apple jako „działa zgodnie z przeznaczeniem”. Jakiś czas temu zgłosiłem błąd. Ich rozumowanie polega na tym, że użytkownik często wprowadza dane w formie modalnej, więc stara się być „pomocny” i utrzymywać klawiaturę widoczną tam, gdzie zwykle różne przejścia w widoku modalnym mogą powodować wielokrotne pokazywanie / ukrywanie klawiatury.

edycja: oto odpowiedź inżyniera Apple na forach programistów:

Czy Twój pogląd był przypadkiem przedstawiony w stylu UIModalPresentationFormSheet? Aby uniknąć częstych animacji typu „wejście i wyjście”, klawiatura czasami pozostaje na ekranie, nawet jeśli nie ma pierwszej odpowiedzi. To nie jest błąd.

Daje to wielu ludziom problemy (łącznie ze mną), ale w tej chwili wydaje się, że nie ma sposobu na obejście tego.

AKTUALIZACJA:

W iOS 4.3 i nowszych możesz teraz zaimplementować `-disablesAutomaticKeyboardDismissal 'na kontrolerze widoku, aby zwrócić NIE:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

To rozwiązuje problem.

Mike Weller
źródło
7
pauza Wow, dobrze. Wielkie dzięki za heads-upy. Cholera Apple .. :(
Kalle
Czy przesłałeś raport o błędzie do Apple? Zrobiłem to pod numerem ID 8384423. Złożyłem również przykładowy wniosek w celu odtworzenia zachowania.
Shaggy Frog
3
Począwszy od iOS 4.3, istnieje teraz metoda disablesAutomaticKeyboardDismissal, która rozwiązuje ten problem.
Kalle
5
próbuję, że wyłącza metodę AutomaticKeyboardDismissal, ale nadal nie rozwiązał problemu, jak go rozwiązać?
R. Dewi
3
@Snips: Musisz utworzyć UINavigationControllerpodklasę, która będzie nadpisywać, disablesAutomaticKeyboardDismissalaby powrócić NOi używać jej jako kontrolera nawigacji podczas prezentacji modalnego arkusza formularza. Zobacz odpowiedź @ miha-hribar poniżej.
Pascal
149

Bądź ostrożny, jeśli wyświetlasz modal za pomocą UINavigationController. Następnie należy ustawić disablesAutomaticKeyboardDismissalna kontrolerze nawigacyjnym, a nie na kontrolerze widoku. Możesz to łatwo zrobić za pomocą kategorii.

Plik: UINavigationController + KeyboardDismiss.h

#import <Foundation/Foundation.h>

@interface UINavigationController (KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal;

@end

Plik: UINavigationController + KeyboardDismiss.m

#import "UINavigationController+KeyboardDismiss.h"

@implementation UINavigationController(KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal
{
    return NO;
}

@end

Nie zapomnij zaimportować kategorii do pliku, w którym używasz UINavigationController.

Miha Hribar
źródło
19
+1, wreszcie widzę brakującą informację o tym numerze podkreślił: że trzeba zastąpić disablesAutomaticKeyboardDismissalz UINavigationControllernie własnego kontrolera widoku, aby rozwiązać ten problem.
DarkDust
Miły! Dokładnie to, czego potrzebowałem. Dziękuję Ci.
Justin
Idealny. Nie jest to jasne z oficjalnych dokumentów, ale ma sens, ponieważ UINavigationController znajduje się w łańcuchu odpowiadającym. Doskonała odpowiedź. Dziękuję Ci!
imnk
1
Prezentuję modalne okno dialogowe z UISplitViewController. Próbowałem powyższego kodu, ale podstawiłem UISplitViewController do UINavigationController, ale nadal nie działa. Czy ta metoda powinna również działać na UISplitViewController?
Snips,
6
Zaimplementowanie zduplikowanej metody w kategorii nie jest dobrym pomysłem. Nigdy nie możesz być pewien, która implementacja zostanie wywołana, więc w najlepszym razie możesz spodziewać się niespójnego zachowania. Lepiej odziedziczyć po UINavigationController i zastąpić metodę w klasie niestandardowej.
Sean
51

Rozwiązałem ten problem, używając UIModalPresentationPageSheetstylu prezentacji i zmieniając jego rozmiar natychmiast po jego prezentacji. Tak jak:

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];
azdev
źródło
Hmmm ... to nie do końca dobrze ... zmiana rozmiaru powoduje, że modal maluje się zabawnie ... to tak, jakby ściśnął zawartość, aby zmieściła się w pudełku nowego rozmiaru lub coś ... wszystko wygląda śmiesznie. :(
toofah
Występują również problemy z rotacją tego ... jeśli obrócisz się, gdy ten modal jest
włączony,
2
toofah, edytowałem kod, aby poradzić sobie z problemem kurczenia się / wzrostu podczas obracania; wystarczy nadać superwizji elastyczny górny i dolny margines. Nie jestem pewien, czy widzę inne zachowanie.
azdev
1
działa to tylko, o ile nie przesuniesz innego widoku nad tym. Ponieważ po zamknięciu widoku wysuniętego nad prezentowany widok UIModalPresentationPageSheet powraca do pierwotnego rozmiaru.
V1ru8
Zadziałało. Ale słowo w widoku wygląda trochę rozmazane. Nie wiem dlaczego.
jeswang
1

Jeśli przełączysz inny wyświetlacz modalny, możesz sprawić, że klawiatura zniknie. Nie jest ładna i nie ożywia, ale możesz sprawić, że odejdzie.

Byłoby wspaniale, gdyby była poprawka, ale na razie to działa. Możesz zaklinować go w kategorii UIViewControlleri zadzwonić, kiedy chcesz, aby klawiatura zniknęła:

@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

Bądź ostrożny z tym podczas przeglądaniaDidAppear / viewDidDisappear i wszystkie te metody zostaną wywołane. Jak powiedziałem, nie jest ładny, ale działa.

-Adam

Adam
źródło
1

Możesz również obejść ten problem w uniwersalnej aplikacji, po prostu sprawdzając idiom, a jeśli jest to iPad, w ogóle nie otwieraj klawiatury automatycznie i pozwól użytkownikowi dotknąć tego, co chce edytować.

Może nie jest to najlepsze rozwiązanie, ale jest bardzo proste i nie wymaga żadnych wymyślnych hacków, które zepsują się w następnej wersji iOS :)

Maciej Swic
źródło
1

Umieść ten kod w widokuWillDisappear: metoda bieżącego kontrolera to inny sposób, aby to naprawić:

Class UIKeyboardImpl = NSClassFromString(@"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:@selector(activeInstance)];
[activeInstance performSelector:@selector(dismissKeyboard)];
Fabuła
źródło
1

Przekonałem się, że disablesAutomaticKeyboardDismissaldodanie disablesAutomaticKeyboardDismissalfunkcji nie działa w moim przypadkuUITextField modalnym oknie dialogowym.

Klawiatura ekranowa po prostu nie zniknie.

Moim rozwiązaniem było wyłączenie wszystkich elementów sterujących wprowadzaniem tekstu w moim oknie dialogowym, a następnie ponowne włączenie odpowiednich ułamków sekundy później.

Wydaje się, że gdy iOS widzi, że żadna z UITextFieldkontroli są włączone, to nie pozbyć klawiaturze.

Mike Gledhill
źródło
0

Jestem pewien, że na to spojrzałeś, ale masz pewność, że twoja klasa kontrolera jest poprawnie podłączona jako delegat UITextField, prawda?

Neal L.
źródło
Ustawiam go ręcznie, a metody delegowane są wywoływane, więc tak.
Kalle
0

może nie zwracaj NIE, ale TAK. Więc może odejść.

I masz textFieldShouldEndEditing powracasz TAK?

A dlaczego strzelasz [nextResponder becomeFirstResponder]? przepraszam, widzę teraz

Mam również wiele UITextView, z których wszystkie mają właściwość „edytowalną” ustawioną na FALSE.

Czy możemy założyć, że żaden z nich nie ma tagwartości secondField.tag+1? Jeśli tak, mówisz im, aby zostali pierwszymi osobami odpowiadającymi, zamiast rezygnować z pierwszego odpowiadającego. Być może wstawmy trochę NSLog () do tej struktury if.

mvds
źródło
1
NIE = nie wstawiaj nowego wiersza, z tego co mogę powiedzieć. A ustawienie na TAK nie naprawiło tego.
Kalle
1
Wydaje mi się, że UITextField, z definicji jedna linia, nie ma wiele wspólnego z nowymi liniami. Tak więc chodzi bardziej o przetwarzanie naciśnięcia przycisku Return / Done, jak podano w dokumentacji.
mvds,
Czy jesteś pewien, że wszystko podłączyłeś we właściwy sposób? Czy umieściłeś NSLog("tf %x / method ...",textField);we wszystkich funkcjach delegowania?
mvds
Cóż, funkcje delegowane są odpowiednio wywoływane, i nie byłyby, gdyby delegat nie został odpowiednio skonfigurowany. A NSLog daje EXC_BAD_ACCESS. Ostrzega mnie również przed niezgodnością typu w XCode.
Kalle
Nie. Przepraszam, powinienem to zobaczyć. Zaktualizowałem powyższą odpowiedź o wyniki tych NSLogów, ponieważ formatowanie pojawi się w komunikacie.
Kalle
0

Dla tych, którzy mają problemy z UINavigationController, zobacz moją odpowiedź na podobne pytanie tutaj: https://stackoverflow.com/a/10507689/321785

Edycja: Uważam to za ulepszenie rozwiązania Miha Hribar (ponieważ decyzja jest podejmowana tam, gdzie powinna), a nie komentarz Pascala dotyczący kategorii na UIViewController

Chris Trahey
źródło
0

może nie być idealnym rozwiązaniem, ale działa
[self.view endEditing: YES];
skądkolwiek zaimplementowany jest Twój przycisk lub gest, aby zaprezentować modalność

Tanuj Jagoori
źródło
0
Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}
fivewood
źródło