Подтвердить что ты не робот

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

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

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

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

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

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

Desired behavior

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

Keyboard tearing

4b9b3361

Ответ 1

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

Теперь, чтобы сделать какие-либо анимации между 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

Ответ 2

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

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

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

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

Проблема исправления с frame полностью решает мою проблему.

Если вы столкнулись с такими же проблемами, вы можете попробовать отладить внутренние файлы 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

Ответ 3

Вы можете использовать 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];
             }
         }];
    }
}

EDIT:

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