Klawiatura "WillShow " i" WillHide " kontra rotacja

Mam kontroler widoku nasłuchujący zarówno UIKeyboardWillShowNotification jak i UIKeyboardWillHideNotification. Obsługa tych powiadomień dostosowuje różne części widoku, co jest standardową procedurą.

Poniższy kod jest używany do konwersji rect klawiatury ze współrzędnych ekranu:

CGRect keyboardBounds = [self.view convertRect:[keyboardBoundsValue CGRectValue] fromView:nil];
Znowu standardowa procedura. Niestety, istnieje krytyczna sytuacja, w której konwersja ta nie powiedzie się. Zobacz, co się dzieje, gdy iPhone jest obracany z portretu na krajobraz podczas uruchamiania klawiatury: Nie jest to jednak możliwe, ponieważ nie jest to możliwe.interfejs jest zgłaszany jako portrait ; keyboardBounds.wysokość jest 216.0. to ma sens . Dlaczego? Ponieważ obsługa powiadomień ma szansę "wyczyścić", zanim widok przełączy się w tryb krajobrazowy. Nie jest to jednak możliwe, ponieważ nie jest to możliwe.interface orientation podaje się jako portrait ; keyboardBounds.wysokość jest 480.0. to nie ma sensu . Dlaczego nie? Bo obsługa powiadomień będzie wykonywać swoją pracę myśląc, że wysokość klawiatury wynosi 480.0!

Czy Apple upuściło piłkę, czy robię coś nie tak?

Należy pamiętać, że słuchanie zamiast UIKeyboard did pokazane nie jest poprawnym rozwiązaniem, ponieważ znacznie pogarsza wrażenia użytkownika. Dlaczego? Bo ożywiając moje zmiany w widoku po wystąpieniu animacji wdrażania klawiatury są... wygląda okropnie.

Czy komukolwiek udało się perfekcyjnie uruchomić autorotację podczas uruchamiania klawiatury? Wygląda to na eksplozję chaosu, którą Apple całkowicie przeoczyło. >:|

Author: Voobr, 2012-03-17

7 answers

Może trochę za późno, ale właśnie natknąłem się na ten sam problem i mam na to dobre rozwiązanie, które unika wszelkiego rodzaju pracy (chyba że oczywiście apple coś zmieni)

Zasadniczo, gdy Centrum powiadomień wywoła Twoją metodę dla UIKeyboardWillShowNotification (lub któregokolwiek z innych powiadomień), ramka, którą ci poda dla UIKeyboardFrameBeginUserInfoKey jest w kontekście okna, a nie widoku. Problem z tym polega na tym, że układ współrzędnych windows jest zawsze w pionie, niezależnie od orientacji urządzeń, stąd znajdujesz szerokość i wysokość w złym kierunku.

Jeśli chcesz uniknąć pracy, po prostu przekonwertuj prostokąt na układ współrzędnych widoku(który zmienia się w zależności od orientacji). Aby to zrobić, zrób coś takiego:

- (void) keyboardWillShow:(NSNotification *)aNotification
{
     CGRect keyboardFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect convertedFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];

    ......
    /* Do whatever you want now with the new frame.
     * The width and height will actually be correct now
     */
    ......
}

Mam nadzieję, że to powinno być to, czego szukasz:)

 55
Author: PaReeOhNos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-16 03:40:53

Ostatnio napisałem post na blogu o tym dokładnie problem, który opisałeś i jak go rozwiązać w krótki i elegancki sposób. Oto link do posta: Synchronizacja animacji obrotu między klawiaturą a załączonym widokiem

Jeśli nie chcesz zagłębiać się w długie Wyjaśnienie opisane w poście na blogu, oto krótki opis z przykładem kodu:

Podstawową zasadą jest stosowanie tej samej metody, której używają wszyscy-obserwowanie powiadomień z klawiatury aby animować załączony widok w górę i w dół. Ale oprócz tego musisz anulować te animacje, gdy powiadomienia klawiatury są wywoływane w wyniku zmiany orientacji interfejsu.

Przykład obracania bez anulowania animacji przy zmianie orientacji interfejsu:

Przykład obrotu z anulowaniem animacji przy zmianie orientacji interfejsu:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [[NSNotificationCenter defaultCenter]
            addObserver:self selector:@selector(adjustViewForKeyboardNotification:)
            name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]
            addObserver:self selector:@selector(adjustViewForKeyboardNotification:)
            name:UIKeyboardWillHideNotification object:nil];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    [[NSNotificationCenter defaultCenter]
            removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]
            removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    self.animatingRotation = YES;
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    self.animatingRotation = NO;
}

- (void)adjustViewForKeyboardNotification:(NSNotification *)notification {
    NSDictionary *notificationInfo = [notification userInfo];

    // Get the end frame of the keyboard in screen coordinates.
    CGRect finalKeyboardFrame = [[notificationInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

    // Convert the finalKeyboardFrame to view coordinates to take into account any rotation
    // factors applied to the window’s contents as a result of interface orientation changes.
    finalKeyboardFrame = [self.view convertRect:finalKeyboardFrame fromView:self.view.window];

    // Calculate new position of the commentBar
    CGRect commentBarFrame = self.commentBar.frame;
    commentBarFrame.origin.y = finalKeyboardFrame.origin.y - commentBarFrame.size.height;

    // Update tableView height.
    CGRect tableViewFrame = self.tableView.frame;
    tableViewFrame.size.height = commentBarFrame.origin.y;

    if (!self.animatingRotation) {
        // Get the animation curve and duration
        UIViewAnimationCurve animationCurve = (UIViewAnimationCurve) [[notificationInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
        NSTimeInterval animationDuration = [[notificationInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

        // Animate view size synchronously with the appearance of the keyboard. 
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:animationDuration];
        [UIView setAnimationCurve:animationCurve];
        [UIView setAnimationBeginsFromCurrentState:YES];

        self.commentBar.frame = commentBarFrame;
        self.tableView.frame = tableViewFrame;

        [UIView commitAnimations];
    } else {
        self.commentBar.frame = commentBarFrame;
        self.tableView.frame = tableViewFrame;
    }
}

Ta odpowiedź została również zamieszczona w podobnym pytaniu: UIView na klawiaturze podobne do aplikacja iMessage

 4
Author: smnh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:15

Spotkałem się z tym samym problemem. iOS podał mi nieprawidłową szerokość / wysokość klawiatury. Użyłem poniższego snipped w handlerze keyboardDidShow:

CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGSize keyboardSize2 = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
LogDbg(@"keyboard size: frameBegin=%@; frameEnd=%@", NSStringFromCGSize(keyboardSize), NSStringFromCGSize(keyboardSize2));

A dla trybów pionowych i poziomych iPada mam odpowiednio:

2012-06-14 04:09:49.734 -[LoginViewController keyboardDidShow:] 132 [DBG]:keyboard size: frameBegin={768, 264}; frameEnd={768, 264}
2012-06-14 04:10:07.971 -[LoginViewController keyboardDidShow:] 132 [DBG]:keyboard size: frameBegin={352, 1024}; frameEnd={352, 1024}

Zgadując, że szerokość klawiatury powinna być większa niż wysokość (tak, jestem tak naiwny) zrobiłem obejście takie jak poniżej:

if (keyboardSize.width < keyboardSize.height)
{
    // NOTE: fixing iOS bug: http://stackoverflow.com/questions/9746417/keyboard-willshow-and-willhide-vs-rotation
    CGFloat height = keyboardSize.height;
    keyboardSize.height = keyboardSize.width;
    keyboardSize.width = height;
}
 3
Author: Sneg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-14 01:16:25

Cóż, spróbuj spojrzeć na szerokość klawiatury. Jeśli jest to wartość, której oczekujesz, to zakładam, że wartości są po prostu przełączane ;). 480 ma sens jako szerokość klawiatury do wchodzenia w krajobraz, co daje mi to przeczucie.

Jeśli to się nie powiedzie, po prostu zapisz prostokąty pionowe i poziome osobno. Są one dobrze udokumentowane ;)

 0
Author: borrrden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-17 01:44:16

Wiem, że to bardzo późna odpowiedź. Teraz tylko przyszedłem w tej sytuacji i znaleźć pytanie bez odpowiedzi. Więc pomyślałem, że podzielę się moim rozwiązaniem. Będzie inny lepszy sposób, ale w następujący sposób również możemy rozwiązać ten problem.

Kbkeyboardhandler, którego użyłem pochodzi z: UITextField: move view when keyboard appears

Właśnie zmieniłem mojego delegata w następujący sposób:

- (void)keyboardSizeChanged:(CGSize)delta
{    
    CGRect frame = self.view.frame;    
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    switch (interfaceOrientation) {
        case UIInterfaceOrientationPortrait:
            frame.origin.y-=delta.height;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            frame.origin.y+=delta.height;
            break;
        case UIInterfaceOrientationLandscapeLeft:
            frame.origin.x-=delta.height;
            break;
        case UIInterfaceOrientationLandscapeRight:
            frame.origin.x+=delta.height;
            break;
        default:
            break;
    }
    self.view.frame = frame;
}
I działało dobrze.
 0
Author: Shineeth Hamza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:34

Oto moje obejście:

CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float keyboardHeight = self.interfaceOrientation == UIInterfaceOrientationPortrait ? keyboardSize.height : keyboardSize.width;

Mam nadzieję, że to pomoże:)

 -1
Author: thanhbinh84,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-21 03:24:03

Używam poniższego kodu, aby uzyskać rozmiar klawiatury, który działa dobrze dla wszystkich obrotów

NSDictionary *info = [aNotification userInfo];
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
  kbHeight = [[NSNumber numberWithFloat:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.width] floatValue];
else
  kbHeight = [[NSNumber numberWithFloat:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height] floatValue];
NSLog(@"keyboard height = %F",kbHeight);

Następnie testuję orientację za pomocą orientacji paska stanu (która działa w pierwszym przypadku uruchamiania dla iPada) i przesuwam widok w kierunku względnym potrzebnym do zrobienia miejsca na klawiaturze. Działa to doskonale, jeśli klawiatura jest widoczna, to przesuwa się do właściwej pozycji na obrotach.

UIDeviceOrientation orientation =  [UIApplication sharedApplication].statusBarOrientation;


if (orientation == UIDeviceOrientationPortrait)
  {
  NSLog(@"Orientation: portrait");
  self.originalCenter = self.view.center;
  self.view.center = CGPointMake(self.originalCenter.x, self.originalCenter.y-kbHeight);
  }

if (orientation == UIDeviceOrientationPortraitUpsideDown)
  {
  NSLog(@"Orientation: portrait upside down");
  self.originalCenter = self.view.center;
  self.view.center = CGPointMake(self.originalCenter.x, self.originalCenter.y+kbHeight);
  }

if (orientation == UIDeviceOrientationLandscapeLeft)
  {
  NSLog(@"Orientation: landscape left");
  self.originalCenter = self.view.center;
  self.view.center = CGPointMake(self.originalCenter.x+kbHeight,self.originalCenter.y);
  }

if (orientation == UIDeviceOrientationLandscapeRight)
  {
  NSLog(@"Orientation: landscape right");
  self.originalCenter = self.view.center;
  self.view.center = CGPointMake(self.originalCenter.x-kbHeight,self.originalCenter.y);
  }

Możesz powrócić do pierwotnej pozycji widoku, gdy klawiatura znika lub za pomocą funkcji textFileDidEndEditing.

 -1
Author: FiddleMeRagged,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-02 17:59:08