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

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

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.


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.


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

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


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 :)


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

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.


0

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


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.


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


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ść


0
Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.