Анимируйте клавиатуру, синхронизированную с UIView, при переходе назад в iOS7
Я хотел бы, чтобы подобное поведение было похоже на приложение "Сообщения" (также распространенное в большинстве текстовых приложений) в iOS7, где в режиме просмотра разговора прямо с левого края экрана будет вести себя как кнопка "Назад" в UINavigationController.
Мне удалось реализовать это поведение, однако, если клавиатура открыта в представлении представления, когда я начинаю отскакивать назад, клавиатура застревает и не оживляет вид справа, когда я перемещаю палец. Я хотел бы анимировать клавиатуру и представление представления как единое целое, не так, как если бы клавиатура находилась поверх других представлений, и они анимируются позади нее, что я получаю сейчас (см. Второй снимок экрана):
(ОБНОВЛЕНИЕ:) Обратите внимание, что клавиатура в конце концов исчезнет после завершения анимации основного вида, на чем я сосредоточен, - позиция клавиатуры во время процесса салфетки, и когда вы продолжаете касаться устройства половину пути, который не синхронизируется с фактическим видом. Второй снимок экрана разъясняет это желаемое поведение. Я также задаюсь вопросом, почему он не является стандартным.)
Легко реплицировать проблему, просто создав новое приложение iPhone с основными деталями в Xcode 5.0.2 и добавив текстовое поле в подробный вид (желательно где-то в верхней половине) в StoryBoard, запустив приложение, добавив элемент, нажав на него, чтобы перейти к подробному представлению и нажав на добавленное текстовое поле. Проведите по краю с левой стороны устройства, удерживая палец на нем, и вы увидите проблему.
Желаемое поведение:
![Desired behavior]()
Текущее поведение:
![Keyboard tearing]()
Ответы
Ответ 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
).