Анимируйте клавиатуру синхронно с UIView, одновременно смахивая края назад в iOS7

Я хотел бы получить поведение, подобное приложению "Сообщения" (также распространенное в большинстве приложений для работы с текстовыми сообщениями) в iOS7, где в представлении беседы, проведенном вправо от левого края экрана, будет действовать как кнопка "Назад" в UINavigationController.

Мне удалось реализовать это поведение, однако, если клавиатура открыта в представлении представления, когда я начинаю проводить пальцем назад, клавиатура застревает и не анимируется с видом вправо, когда я двигаю пальцем. Я хотел бы анимировать клавиатуру и представление представления как одно целое, а не так, как будто клавиатура находится поверх других представлений, и они анимируются позади нее, что я и получаю сейчас (см. Второй снимок экрана):

(ОБНОВЛЕНИЕ: обратите внимание, что клавиатура со временем исчезнет после завершения анимации основного вида; на что я обращаю внимание - это положение клавиатуры во время процесса пролистывания и когда вы продолжаете касаться устройства на половине пути, который не находится в синхронизировать с фактическим видом. Второй снимок экрана поясняет это желаемое поведение. Мне также интересно, почему это не по умолчанию.)

Эту проблему легко воспроизвести, просто создав новое приложение iPhone с мастер-деталями в Xcode 5.0.2 и добавив текстовое поле в подробное представление (предпочтительно где-то в верхней половине) в StoryBoard, запустив приложение, добавив элемент, нажав на него, чтобы перейти к подробному виду и нажав на текстовое поле, которое вы добавили. Проведите по краю с левой стороны устройства, удерживая на нем палец, и вы увидите проблему.

Желаемое поведение:

Желаемое поведение

Текущее поведение:

Разрыв клавиатуры

3 ответа

Решение

К сожалению, нет встроенного метода для этого. Я очень надеюсь, что будет что-то вроде UIScrollViewKeyboardDismissModeInteractive за UIViewControllers.

На данный момент, чтобы сделать любую анимацию между viewControllers, вы должны использовать transitionCoordinator:

- (BOOL)animateAlongsideTransition:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))animation
                        completion:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))completion;

- (BOOL)animateAlongsideTransitionInView:(UIView *)view
                               animation:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))animation
                              completion:(void (^)(id <UIViewControllerTransitionCoordinatorContext>context))completion;

Для клавиатуры вы должны сделать что-то вроде этого:

[self.transitionCoordinator animateAlongsideTransitionInView:self.keyboardSuperview
                                                   animation:
^(id<UIViewControllerTransitionCoordinatorContext> context) {
    self.keyboardSuperview.x = self.view.width;
}
                                                  completion:nil];

Что касается keyboardSuperview - вы можете получить это, создав подделку inputAccessoryView:

self.textField.inputAccessoryView = [[UIView alloc] init];

Тогда супервьюз будет self.textField.inputAccessoryView.superview

Это должно просто работать автоматически, но иногда это не из-за некоторых условий.

Если текущий firstResponder находится внутри активного UIViewController и уволить UINavigationController Механизм, ожидаемая анимация клавиатуры (горизонтальная) будет выполняться автоматически. Поэтому иногда это поведение по умолчанию нарушается другими странными факторами, и клавиатура начинает исчезать с анимацией скольжения вместо горизонтальной анимации.

Я провел несколько дней с отладкой внутреннего UIKit материала (вокруг методов needDeferredTransition, allowCustomTransition и другое) найти один особый фактор, который играет ключевую роль в моем случае.

Я обнаружил, что логика внутри UIPeripheralHost проверки frame тока UIViewConrollerвид, frame из UINavigationControllerвид (контейнер) и экран size и, если все это не равно друг другу, UIPeripheralHost решает, что текущая ситуация выглядит как модальное окно, и устанавливает флаг allowCustomTransition = NO, Это отключение UINavigationControllerгоризонтальная анимация

Исправление проблемы с frameS полностью решает мою проблему.

Если у вас возникли те же проблемы, вы можете попытаться отладить внутренний UIKit-контент вокруг этих частных методов и найти условия, которые отключают горизонтальную анимацию:

https://github.com/JaviSoto/iOS8-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIPeripheralHost.h

https://github.com/JaviSoto/iOS8-Runtime-Headers/blob/master/Frameworks/UIKit.framework/_UIViewControllerKeyboardAnimationStyle.h

Вы можете использовать https://github.com/cotap/TAPKeyboardPop если вам не нужно ничего особенного.

В моем случае у меня есть некоторая логика, связанная с UIKeyboardWillShowNotification а также UIKeyboardWillHideNotification которые были уволены по жесту "смахивание к спине". Я объединяю этот ответ и TAPKeyboardPop и вот что у меня есть:

- (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated {
    [super beginAppearanceTransition:isAppearing animated:animated];
    if (isAppearing || !animated || !_keyboardIsShown) {
        return;
    }
    if ([self respondsToSelector:@selector(transitionCoordinator)]) {
        UIView *keyboardView = self.searchBar.inputAccessoryView.superview;
        [self.searchBar becomeFirstResponder];
        [self.transitionCoordinator animateAlongsideTransitionInView:keyboardView
                                                           animation:^(id<UIViewControllerTransitionCoordinatorContext> context)
         {
             CGRect endFrame = CGRectOffset(keyboardView.frame, CGRectGetWidth(keyboardView.frame), 0);
             keyboardView.frame = endFrame;
         } completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
         {
             if (![context isCancelled]) {
                 [self.searchBar resignFirstResponder];
             }
         }];
    }
}

РЕДАКТИРОВАТЬ:

Я добавил> поддержку iOS7 и логику, чтобы знать, когда клавиатура отображается (_keyboardIsShown установлен в UIKeyboardWillShowNotification/UIKeyboardWillHideNotification или в UIKeyboardDidHideNotification/UIKeyboardDidShowNotification).

Другие вопросы по тегам