UITextField: перемещение вида при появлении клавиатуры

В настоящее время я работаю над iPhone-приложением с одним представлением, которое имеет несколько UITextFields для ввода. Когда клавиатура показывает, она накладывает нижние текстовые поля. Поэтому я добавил соответствующий метод textFieldDidBeginEditing: чтобы переместить представление вверх, что отлично работает:

 - (void)textFieldDidBeginEditing:(UITextField *)textField { if ( ( textField != inputAmount ) && ( textField != inputAge ) ) { NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y -= kOFFSET_FOR_KEYBOARD; frame.size.height += kOFFSET_FOR_KEYBOARD; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; } } 

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

Я также добавил метод textFieldDidEndEnditing: который снова перемещает представление вниз (и обновляет некоторые объекты модели в соответствии с измененным вводом):

 - (void)textFieldDidEndEditing:(UITextField *)textField { if ( ( textField != inputMenge ) && ( textField != inputAlter ) ) { NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y += kOFFSET_FOR_KEYBOARD; frame.size.height -= kOFFSET_FOR_KEYBOARD; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; } // Additional Code } 

Однако это решение имеет простой недостаток: когда я заканчиваю редактирование одного из «скрытых» текстовых полей и касаюсь другого текстового поля, клавиатура исчезает, вид перемещается вниз, вид снова перемещается, и клавиатура снова появляется.

Есть ли возможность удержать клавиатуру от исчезновения и повторного появления между двумя изменениями («скрытых» текстовых полей – так, что представление перемещается только тогда, когда выбранное текстовое поле изменяется от того, которое будет скрыто клавиатурой, до того, что не будет скрыто )?

Это решение основано на ComSubVie’s.

Преимущества:

  • Он поддерживает rotation устройства – работает для всех ориентаций;
  • Он не кодирует значения продолжительности анимации и кривой, он читает их из уведомления клавиатуры;
  • Он использует UIKeyboardWillShowNotification вместо UIKeyboardDidShowNotification для синхронизации анимации клавиатуры и пользовательских действий;
  • Он не использует устаревший UIKeyboardBoundsUserInfoKey ;
  • Он обрабатывает изменение размера клавиатуры из-за нажатия клавиши International;
  • Исправлена ​​утечка памяти путем незарегистрирования событий клавиатуры;
  • Весь код обработки клавиатуры инкапсулирован в отдельный class – KBKeyboardHandler ;
  • Гибкость – class KBKeyboardHandler может быть легко расширен / изменен для лучшего удовлетворения конкретных потребностей;

Ограничения:

  • Работы для iOS 4 и выше, он нуждается в небольших модификациях для поддержки более старых версий;
  • Он работает для приложений с одним UIWindow . Если вы используете несколько UIWindows, вам может потребоваться изменить метод retrieveFrameFromNotification: .

Применение:

Включите KBKeyboardHandler.h, KBKeyboardHandler.m и KBKeyboardHandlerDelegate.h в свой проект. Реализовать протокол KBKeyboardHandlerDelegate в вашем controllerе представления – он состоит из одного метода, который будет вызываться при отображении клавиатуры, скрытии или изменении размера. KBKeyboardHandler экземпляр KBKeyboardHandler и установите его делегат (обычно сам). См. Пример MyViewController ниже.

KBKeyboardHandler.h :

 #import  #import  @protocol KBKeyboardHandlerDelegate; @interface KBKeyboardHandler : NSObject - (id)init; // Put 'weak' instead of 'assign' if you use ARC @property(nonatomic, assign) id delegate; @property(nonatomic) CGRect frame; @end 

KBKeyboardHandler.m :

 #import "KBKeyboardHandler.h" #import "KBKeyboardHandlerDelegate.h" @implementation KBKeyboardHandler - (id)init { self = [super init]; if (self) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } @synthesize delegate; @synthesize frame; - (void)keyboardWillShow:(NSNotification *)notification { CGRect oldFrame = self.frame; [self retrieveFrameFromNotification:notification]; if (oldFrame.size.height != self.frame.size.height) { CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width, self.frame.size.height - oldFrame.size.height); if (self.delegate) [self notifySizeChanged:delta notification:notification]; } } - (void)keyboardWillHide:(NSNotification *)notification { if (self.frame.size.height > 0.0) { [self retrieveFrameFromNotification:notification]; CGSize delta = CGSizeMake(-self.frame.size.width, -self.frame.size.height); if (self.delegate) [self notifySizeChanged:delta notification:notification]; } self.frame = CGRectZero; } - (void)retrieveFrameFromNotification:(NSNotification *)notification { CGRect keyboardRect; [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect]; self.frame = [[UIApplication sharedApplication].keyWindow.rootViewController.view convertRect:keyboardRect fromView:nil]; } - (void)notifySizeChanged:(CGSize)delta notification:(NSNotification *)notification { NSDictionary *info = [notification userInfo]; UIViewAnimationOptions curve; [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve]; NSTimeInterval duration; [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration]; void (^action)(void) = ^{ [self.delegate keyboardSizeChanged:delta]; }; [UIView animateWithDuration:duration delay:0.0 options:curve animations:action completion:nil]; } @end 

KBKeyboardHandlerDelegate.h :

 @protocol KBKeyboardHandlerDelegate - (void)keyboardSizeChanged:(CGSize)delta; @end 

Пример MyViewController.h :

 @interface MyViewController : UIViewController ... @end 

Образец MyViewController.m :

 @implementation MyViewController { KBKeyboardHandler *keyboard; } - (void)dealloc { keyboard.delegate = nil; [keyboard release]; [super dealloc]; } - (void)viewDidLoad { [super viewDidLoad]; keyboard = [[KBKeyboardHandler alloc] init]; keyboard.delegate = self; } - (void)viewDidUnload { [super viewDidUnload]; keyboard.delegate = nil; [keyboard release]; keyboard = nil; } - (void)keyboardSizeChanged:(CGSize)delta { // Resize / reposition your views here. All actions performed here // will appear animated. // delta is the difference between the previous size of the keyboard // and the new one. // For instance when the keyboard is shown, // delta may has width=768, height=264, // when the keyboard is hidden: width=-768, height=-264. // Use keyboard.frame.size to get the real keyboard size. // Sample: CGRect frame = self.view.frame; frame.size.height -= delta.height; self.view.frame = frame; } 

ОБНОВЛЕНИЕ: Исправлено предупреждение iOS 7, спасибо @weienv.

Я просто решил эту проблему. Решение представляет собой комбинацию наблюдателя UIKeyboardDidShowNotification и UIKeyboardDidHideNotification с вышеупомянутыми textFieldDidBeginEditing: и textFieldDidEndEditing:

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

Вот как UITextField два UITextField делегата UITextField :

 - (void)textFieldDidBeginEditing:(UITextField *)textField { activeField = textField; } - (void)textFieldDidEndEditing:(UITextField *)textField { activeField = nil; // Additional Code } 

Когда представление загружено, создаются следующие два наблюдателя:

 - (void)viewDidLoad { // Additional Code [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasHidden:) name:UIKeyboardDidHideNotification object:nil]; } 

И соответствующие методы реализуются следующим образом:

 - (void)keyboardWasShown:(NSNotification *)aNotification { if ( keyboardShown ) return; if ( ( activeField != inputAmount ) && ( activeField != inputAge ) ) { NSDictionary *info = [aNotification userInfo]; NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y -= keyboardSize.height-44; frame.size.height += keyboardSize.height-44; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; viewMoved = YES; } keyboardShown = YES; } - (void)keyboardWasHidden:(NSNotification *)aNotification { if ( viewMoved ) { NSDictionary *info = [aNotification userInfo]; NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y += keyboardSize.height-44; frame.size.height -= keyboardSize.height-44; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; viewMoved = NO; } keyboardShown = NO; } 

Этот код работает сейчас, как ожидалось. Клавиатура отбрасывается только при нажатии кнопки «Готово», в противном случае она остается видимой, а вид не перемещается.

В качестве дополнительной заметки, я думаю, что можно динамически NSNotification , NSNotification объект NSNotification , так как я уже играл с аналогичным решением, но не получил его для работы (что теперь и происходит).

Этот controller представления должен быть UITextView Delegate, и вы должны установить self.textview.delegate = self in viewdidload

  -(void) textViewDidBeginEditing:(UITextView *)textView { NSLog(@"%f",self.view.frame.origin.y); [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.25f]; CGRect frame = self.view.frame; frame.origin.y =frame.origin.y -204; [self.view setFrame:frame]; [UIView commitAnimations]; } -(void) textViewDidEndEditing:(UITextView *)textView { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.25f]; CGRect frame = self.view.frame; frame.origin.y = frame.origin.y + 204; [self.view setFrame:frame]; [UIView commitAnimations]; } 

Я получил вашу проблему, просто простую вещь, просто дайте выход в UIScrollview. установите уникальное свойство Tag для каждого текстового поля.

 -(void)textFieldDidBeginEditing:(UITextField *)textField { switch (textField.tag) { case 2: //can be your textfiled tag { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-150); //set figure y-150 as per your comfirt [scrollview setContentOffset:scrollPoint animated:YES]; }break; case 3: { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-180); //set figure y-180 as per your comfirt [scrollview setContentOffset:scrollPoint animated:YES]; }break; ... } } -(void)textFieldDidEndEditing:(UITextField *)textField{ if(textField.tag==3){ [scrollview setContentOffset:CGPointZero animated:YES]; } //set the last textfield when you want to disappear keyboard. } 
 Write below code in your view controller. tbl is your table view. -(void)viewWillAppear:(BOOL)animated{ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } -(void) viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } #pragma mark - Keyboard Methods -(void)keyboardWillShow:(NSNotification *)notification { // 375 × 667 ( 750 × 1334 ) iPhone 6 //414 × 736 CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; int H = [[UIScreen mainScreen] bounds].size.height - 64- 20 -keyboardRect.size.height; [UIView animateWithDuration:0.5 animations:^{ tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right); }]; } -(void)keyboardWillChangeFrame:(NSNotification *)notification { CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; // int H = IS_IPHONE_5?504-keyboardRect.size.height:416-keyboardRect.size.height; int H = [[UIScreen mainScreen] bounds].size.height - 64- 20 -keyboardRect.size.height; [UIView animateWithDuration:0.5 animations:^{ // scroll.frame = rect; tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right); }]; } -(void)keyboardWillHide:(NSNotification *)notification { [UIView animateWithDuration:0.3 animations:^{ // scroll.frame = rect; tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, 0, tbl.contentInset.right); }]; } 

Довольно простое решение, работает со всеми размерами экрана

Сначала вы должны включить UITextFields в UIScrollView. В моем случае у меня было несколько UITextFields и UITextView.

введите описание изображения здесь

Затем вам нужно наследовать UITextFieldDelegate, UITextViewDelegate.

class SettingsVC: UIViewController, UITextFieldDelegate, UITextViewDelegate

Назначьте делегатов текстового поля и текстового представления.

fullNameTextField.delegate = self usernameTextField.delegate = self websiteTextField.delegate = self profileDescription.delegate = self

Затем используйте этот код:

 var editingTextInput: UIView! override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardShown(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil) } func keyboardShown(notification: NSNotification) { if let infoKey = notification.userInfo?[UIKeyboardFrameEndUserInfoKey], let rawFrame = (infoKey as AnyObject).cgRectValue { let keyboardFrame = view.convert(rawFrame, to: view) let editingTextInputFrame = self.editingTextInput.convert(self.editingTextInput.frame, to: view) if editingTextInputFrame.maxY > keyboardFrame.minY{ let diff = keyboardFrame.minY - editingTextInputFrame.maxY containerScrollView.setContentOffset(CGPoint(x: 0, y: -diff), animated: true) } } } func textFieldDidBeginEditing(_ textField: UITextField) { self.editingTextInput = textField } func textViewDidBeginEditing(_ textView: UITextView) { self.editingTextInput = textView } func textFieldDidEndEditing(_ textField: UITextField) { containerScrollView.setContentOffset(CGPoint.zero, animated: true) } func textViewDidEndEditing(_ textView: UITextView) { containerScrollView.setContentOffset(CGPoint.zero, animated: true) } 
  • Как отправить данные json в запрос Http с помощью NSURLRequest
  • Создайте эскиз или изображение AVPlayer в текущее время
  • Определение типа устройства
  • Могу ли я передать блок как @selector с Objective-C?
  • Вам нужно создать NSAutoreleasePool в блоке в GCD?
  • Ошибка AdMob с помощью : непризнанный селектор
  • Процедура отправки сообщений iOS 6 Facebook заканчивается ошибкой «remote_app_id не соответствует сохраненному id»
  • drawRect не вызывается в моем подclassе UIImageView
  • Сохранение UIColor и загрузка из NSUserDefaults
  • Установка UIDatePicker в таблицу UIActionSheet
  • UIDatePicker, устанавливающий максимальные и минимальные даты на основе сегодняшней даты
  • Давайте будем гением компьютера.