Обработка клавиатуры так же, как в приложении Messages в iOS 7
Я реализую представление, которое в некотором роде похоже на то, что происходит в приложении Messages, поэтому есть представление с UITextView, прикрепленным к нижней части экрана, и есть также UITableView, показывающий основное содержимое. Когда он нажат, он скользит вверх вместе с клавиатурой, а когда клавиатура отклонена, он скользит обратно в нижнюю часть экрана.
Эта часть у меня есть, и она отлично работает - я только что подписался на уведомления клавиатуры - спрячется и покажет.
Проблема дело в том, что я установил режим отключения клавиатуры на UITableView в интерактивный, и я не могу захватить изменения клавиатуры, когда она панорамируется.
Вторая проблема заключается в том, что этот бар с uitextview покрывает некоторую часть uitableview. Как это исправить? Я все еще хочу, чтобы uitableview был "под" этой панелью, как и в приложении messages.
Я использую AutoLayout во всех местах.
Любая помощь будет оценена по достоинству!
============
EDIT1:
Вот некоторый код:
Вид Иерархия выглядит следующим образом:
Вид
- UITableView (этот будет содержать " сообщения")
- UIView (этот будет скользить)
UITableView имеет ограничения на верхний, левый, правый и Нижний Родительский вид, поэтому он заполняет весь экран.
UIView имеет ограничения слева, справа и снизу родительского вида, поэтому он приклеен к нижней части - я переместил его, настроив константу на ограничение.
В методе ViewWillAppear:
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.DidShowNotification, OnKeyboardDidShowNotification);
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillChangeFrameNotification, OnKeyboardDidShowNotification);
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillHideNotification, OnKeyboardWillHideNotification);
И вот методы:
void OnKeyboardDidShowNotification (NSNotification notification)
{
AdjustViewToKeyboard (Ui.KeyboardHeightFromNotification (notification), notification);
}
void OnKeyboardWillHideNotification (NSNotification notification)
{
AdjustViewToKeyboard (0.0f, notification);
}
void AdjustViewToKeyboard (float offset, NSNotification notification = null)
{
commentEditViewBottomConstraint.Constant = -offset;
if (notification != null) {
UIView.BeginAnimations (null, IntPtr.Zero);
UIView.SetAnimationDuration (Ui.KeyboardAnimationDurationFromNotification (notification));
UIView.SetAnimationCurve ((UIViewAnimationCurve)Ui.KeyboardAnimationCurveFromNotification (notification));
UIView.SetAnimationBeginsFromCurrentState (true);
}
View.LayoutIfNeeded ();
commentEditView.LayoutIfNeeded ();
var insets = commentsListView.ContentInset;
insets.Bottom = offset;
commentsListView.ContentInset = insets;
if (notification != null) {
UIView.CommitAnimations ();
}
}
5 ответов:
Я сделал открытый исходный код lib именно для этой цели. Он работает на iOS 7 и 8 и настроен на работу в качестве cocoapod, а также.
Https://github.com/oseparovic/MessageComposerView
Вот пример того, как это выглядит:
Вы можете использовать очень простую функцию
init, как показано ниже, чтобы создать ее с шириной экрана и высотой по умолчанию, например:self.messageComposerView = [[MessageComposerView alloc] init]; self.messageComposerView.delegate = self; [self.view addSubview:self.messageComposerView];Есть несколько других инициализаторов, которые также доступны, чтобы позволить вам настроить рамка, смещение клавиатуры и максимальная высота textview, а также некоторые делегаты для подключения к изменениям кадра и щелчкам кнопок. Смотрите readme для получения дополнительной информации!
Я бы рекомендовал вам переопределить свойство-inputAccessoryView вашего контроллера вида и иметь редактируемый UITextView в качестве его подвида. Кроме того, не забудьте переопределить метод canBecomeFirstResponder, чтобы вернуть YES.
При таком подходе система управляет всем.- (BOOL)canBecomeFirstResponder { if (!RUNNING_ON_IOS7 && !RUNNING_ON_IPAD) { //Workaround for iOS6-specific bug return !(self.viewDisappearing) && (!self.viewAppearing); } return !(self.viewDisappearing); }Есть также некоторые обходные пути, о которых вы должны знать: для UISplitViewController (uisplitviewcontroller detail-only inputAccessoryView ), для ошибок освобождения (UIViewController с inputAccessoryView не освобождается ) и так далее.
ОК, интерактивная клавиатура увольнения отправит уведомление с именем
UIKeyboardDidChangeFrameNotification.Это можно использовать для перемещения текстового представления во время интерактивного отключения клавиатуры.
Вы уже используете этот метод, но отправляете его в Метод
Вам нужен третий метод, который называется что-то вродеOnKeyboardDidShow.keyboardFramedDidChange. Это работает для скрытия и шоу.Для второй задачи вы должны иметь свои вертикальные ограничения, такие как это...
|[theTableView][theTextView (==44)]|Это свяжет от нижней части tableview до верхней части текстового представления.
Это не меняет того, как работает любая анимация, она просто гарантирует, что табличное представление покажет все свое содержимое, независимо от того, видна клавиатура или нет.
Не обновляйте вставки содержимого табличного представления. Используйте ограничения, чтобы убедиться, что фреймы не перекрываются.
П. С. разобраться в вашей схеме. Имена методов начинаются со строчной буквы.
P. P. S. использовать блок на основе анимации.
Я бы попробовал использовать пустой, нулевой высоты
inputAccessoryView. Хитрость заключается в том, чтобы приклеить к нему нижнюю часть текстового поля при появлении клавиатуры, чтобы они двигались вместе. Когда клавиатура исчезнет, вы можете уничтожить это ограничение и снова придерживаться нижней части экрана.
Это решение основано на множестве различных ответов на SO. Это имеет много преимуществ:
- панель Compose остается внизу, когда клавиатура скрыта
- Compose bas следует за клавиатурой, в то время как интерактивный жест на
UITableViewUITableViewCells идут снизу вверх, как в приложении Messages- клавиатура не мешает видеть все
UITableViewCells- должен работать для iOS6, iOS7 и iOS8
Этот код просто работает:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = // . . . // . . . cell.contentView.transform = CGAffineTransformMakeScale(1,-1); cell.accessoryView.transform = CGAffineTransformMakeScale(1,-1); return cell; } - (UIView *)inputAccessoryView { return self.composeBar; } - (BOOL)canBecomeFirstResponder { return YES; } - (void)viewDidLoad { [super viewDidLoad]; self.tableView.transform = CGAffineTransformMakeScale(1,-1); // This code prevent bottom inset animation while appearing view UIEdgeInsets newEdgeInsets = self.tableView.contentInset; newEdgeInsets.top = CGRectGetMaxY(self.navigationController.navigationBar.frame); newEdgeInsets.bottom = self.view.bounds.size.height - self.composeBar.frame.origin.y; self.tableView.contentInset = newEdgeInsets; self.tableView.scrollIndicatorInsets = newEdgeInsets; self.tableView.contentOffset = CGPointMake(0, -newEdgeInsets.bottom); // This code need to be done if you added compose bar via IB self.composeBar.delegate = self; [self.composeBar removeFromSuperview]; [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillChangeFrameNotification object:nil queue:nil usingBlock:^(NSNotification *note) { NSNumber *duration = note.userInfo[UIKeyboardAnimationDurationUserInfoKey]; NSNumber *options = note.userInfo[UIKeyboardAnimationCurveUserInfoKey]; CGRect beginFrame = [note.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; CGRect endFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; UIEdgeInsets newEdgeInsets = self.tableView.contentInset; newEdgeInsets.bottom = self.view.bounds.size.height - endFrame.origin.y; CGPoint newContentOffset = self.tableView.contentOffset; newContentOffset.y += endFrame.origin.y - beginFrame.origin.y; [UIView animateWithDuration:duration.doubleValue delay:0.0 options:options.integerValue << 16 animations:^{ self.tableView.contentInset = newEdgeInsets; self.tableView.scrollIndicatorInsets = newEdgeInsets; self.tableView.contentOffset = newContentOffset; } completion:^(BOOL finished) { ; }]; }]; }Используйте, например
pod 'PHFComposeBarView'составьте бар:@property (nonatomic, strong) IBOutlet PHFComposeBarView *composeBar;И используйте этот класс для представления таблицы:
@interface InverseTableView : UITableView @end @implementation InverseTableView void swapCGFLoat(CGFloat *a, CGFloat *b) { CGFloat tmp = *a; *a = *b; *b = tmp; } - (UIEdgeInsets)contentInset { UIEdgeInsets insets = [super contentInset]; swapCGFLoat(&insets.top, &insets.bottom); return insets; } - (void)setContentInset:(UIEdgeInsets)contentInset { swapCGFLoat(&contentInset.top, &contentInset.bottom); [super setContentInset:contentInset]; } @endЕсли вы хотите, чтобы клавиатура исчезла, нажав на сообщение:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self.composeBar.textView resignFirstResponder]; }Не называйте это, это скроет
composeBarвообще:[self resignFirstResponder];Обновление 2:
Новое решение для отслеживания клавиатуры работает намного лучше:
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // Compose view height growing tracking [self.composeBar addObserver:self forKeyPath:@"frame" options:0 context:nil]; // iOS 7 keyboard tracking [self.composeBar.superview addObserver:self forKeyPath:@"center" options:0 context:nil]; // iOS 8 keyboard tracking [self.composeBar.superview addObserver:self forKeyPath:@"frame" options:0 context:nil]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self.composeBar removeObserver:self forKeyPath:@"frame"]; [self.composeBar.superview removeObserver:self forKeyPath:@"center"]; [self.composeBar.superview removeObserver:self forKeyPath:@"frame"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == self.composeBar.superview || object == self.composeBar) { // Get all values CGPoint newContentOffset = self.tableView.contentOffset; UIEdgeInsets newEdgeInsets = self.tableView.contentInset; UIEdgeInsets newScrollIndicartorInsets = self.tableView.scrollIndicatorInsets; // Update values CGFloat bottomInset = self.view.bounds.size.height - [self.composeBar convertPoint:CGPointZero toView:self.view].y; CGFloat diff = newEdgeInsets.bottom - (bottomInset + 7); newContentOffset.y += diff; newEdgeInsets.bottom = bottomInset + 7; newScrollIndicartorInsets.bottom = bottomInset; // Set all values if (diff < 0 || diff > 40) self.tableView.contentOffset = CGPointMake(0, newContentOffset.y); self.tableView.contentInset = newEdgeInsets; self.tableView.scrollIndicatorInsets = newEdgeInsets; } }

Comments