Как я могу заставить UITextField двигаться вверх, когда клавиатура присутствует?

С iOS SDK:

У меня есть UIView с UITextField которые вызывают клавиатуру. Мне нужно это, чтобы иметь возможность:

  1. Разрешить прокрутку содержимого UIScrollView для просмотра других текстовых полей после поднятия клавиатуры

  2. Автоматически «прыгать» (путем прокрутки) или сокращения

Я знаю, что мне нужен UIScrollView . Я попытался изменить class UIView на UIScrollView но я все еще не могу прокручивать текстовые поля вверх или вниз.

Нужен ли мне UIView и UIScrollView ? Один идет внутри другого?

Что необходимо реализовать, чтобы автоматически перейти к активному текстовому полю?

В идеале такая настройка компонентов, как это возможно, будет выполняться в Interface Builder. Я бы хотел написать только код, для чего он нужен.

Примечание. UIView (или UIScrollView ), с которым я работаю, воспитывается на вкладке ( UITabBar ), которая должна функционировать как обычно.


Изменить: я добавляю полосу прокрутки только для клавиатуры. Даже если это не нужно, я чувствую, что он обеспечивает лучший интерфейс, потому что тогда пользователь может прокручивать и изменять текстовые поля, например.

У меня это работает, когда я изменяю размер кадра UIScrollView когда клавиатура идет вверх и вниз. Я просто использую:

 -(void)textFieldDidBeginEditing:(UITextField *)textField { //Keyboard becomes visible scrollView.frame = CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height - 215 + 50); //resize } -(void)textFieldDidEndEditing:(UITextField *)textField { //keyboard will hide scrollView.frame = CGRectMake(scrollView.frame.origin.x, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height + 215 - 50); //resize } 

Тем не менее, это не автоматически «продвигается» или сосредотачивается на нижние текстовые поля в видимой области, что мне бы очень понравилось.

  1. Вам потребуется только ScrollView если содержимое, которое у вас сейчас, не помещается на экране iPhone. (Если вы добавляете ScrollView качестве ScrollView компонентов, просто чтобы TextField прокручивался вверх, когда клавиатура поднимается, тогда это не нужно.)

  2. Для отображения textfields не скрываемых клавиатурой, стандартным способом является перемещение вверх / вниз по виду с текстовыми полями всякий раз, когда отображается клавиатура.

Вот пример кода:

 #define kOFFSET_FOR_KEYBOARD 80.0 -(void)keyboardWillShow { // Animate the current view out of the way if (self.view.frame.origin.y >= 0) { [self setViewMovedUp:YES]; } else if (self.view.frame.origin.y < 0) { [self setViewMovedUp:NO]; } } -(void)keyboardWillHide { if (self.view.frame.origin.y >= 0) { [self setViewMovedUp:YES]; } else if (self.view.frame.origin.y < 0) { [self setViewMovedUp:NO]; } } -(void)textFieldDidBeginEditing:(UITextField *)sender { if ([sender isEqual:mailTf]) { //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y >= 0) { [self setViewMovedUp:YES]; } } } //method to move the view up/down whenever the keyboard is shown/dismissed -(void)setViewMovedUp:(BOOL)movedUp { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; // if you want to slide up the view CGRect rect = self.view.frame; if (movedUp) { // 1. move the view's origin up so that the text field that will be hidden come above the keyboard // 2. increase the size of the view so that the area behind the keyboard is covered up. rect.origin.y -= kOFFSET_FOR_KEYBOARD; rect.size.height += kOFFSET_FOR_KEYBOARD; } else { // revert back to the normal state. rect.origin.y += kOFFSET_FOR_KEYBOARD; rect.size.height -= kOFFSET_FOR_KEYBOARD; } self.view.frame = rect; [UIView commitAnimations]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // register for keyboard notifications [[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 { [super viewWillDisappear:animated]; // unregister for keyboard notifications while not visible. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } 

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

Вот некоторые вещи, которые следует учитывать, если ваш UIScrollView неправильно прокручивается.

1) Убедитесь, что ваш contentSize больше размера кадра UIScrollView . Способ понять UIScrollViews состоит в том, что UIScrollView похож на окно просмотра содержимого, определенного в contentSize. Поэтому, когда для просмотра UIScrollview в любом месте, contentSize должен быть больше, чем UIScrollView . Кроме того, прокрутки не требуется, поскольку все, что определено в contentSize, уже видно. BTW, default contentSize = CGSizeZero .

2) Теперь, когда вы понимаете, что UIScrollView действительно является окном в вашем «контенте», способ обеспечить, чтобы клавиатура не скрывала ваше окно просмотра UIScrollView's было бы resize UIScrollView чтобы при наличии клавиатуры вы имеют окно UIScrollView размер которого зависит от исходного кадра UIScrollView минус высота клавиатуры. Это гарантирует, что ваше окно будет только той небольшой видимой областью.

3) Вот улов: когда я впервые реализовал это, я решил, что мне нужно будет получить CGRect отредактированного UIScrollView's поля и вызвать метод scrollRecToVisible UIScrollView's . Я UITextFieldDelegate метод textFieldDidBeginEditing с вызовом метода scrollRecToVisible . Это действительно со странным побочным эффектом, что прокрутка будет привязать UITextField к позиции. В течение долгого времени я не мог понять, что это было. Затем я прокомментировал метод textFieldDidBeginEditing Delegate, и все это работает !! (???). Как оказалось, я считаю, что UIScrollView фактически неявно выводит UITextField отредактированный UITextField в видимое окно неявно. Моя реализация метода UITextFieldDelegate и последующего вызова scrollRecToVisible была избыточной и была причиной странного побочного эффекта.

Итак, вот шаги для правильной прокрутки вашего UITextField в UIScrollView на место, когда появляется клавиатура.

 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; // register for keyboard notifications [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:self.view.window]; // register for keyboard notifications [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:self.view.window]; keyboardIsShown = NO; //make contentSize bigger than your scrollSize (you will need to figure out for your own use case) CGSize scrollContentSize = CGSizeMake(320, 345); self.scrollView.contentSize = scrollContentSize; } - (void)keyboardWillHide:(NSNotification *)n { NSDictionary* userInfo = [n userInfo]; // get the size of the keyboard CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; // resize the scrollview CGRect viewFrame = self.scrollView.frame; // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView. viewFrame.size.height += (keyboardSize.height - kTabBarHeight); [UIView beginAnimations:nil context:NULL]; [UIView setAnimationBeginsFromCurrentState:YES]; [self.scrollView setFrame:viewFrame]; [UIView commitAnimations]; keyboardIsShown = NO; } - (void)keyboardWillShow:(NSNotification *)n { // This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown. This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`. If we were to resize the `UIScrollView` again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown. if (keyboardIsShown) { return; } NSDictionary* userInfo = [n userInfo]; // get the size of the keyboard CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; // resize the noteView CGRect viewFrame = self.scrollView.frame; // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView. viewFrame.size.height -= (keyboardSize.height - kTabBarHeight); [UIView beginAnimations:nil context:NULL]; [UIView setAnimationBeginsFromCurrentState:YES]; [self.scrollView setFrame:viewFrame]; [UIView commitAnimations]; keyboardIsShown = YES; } 
  1. Зарегистрировать для уведомлений клавиатуры в viewDidLoad
  2. Отменить viewDidUnload клавиатурных nofitications в viewDidUnload
  3. Убедитесь, что contentSize установлен и больше, чем ваш UIScrollView в viewDidLoad
  4. Сжимайте UIScrollView когда клавиатура присутствует
  5. Верните обратно UIScrollView когда клавиатура уйдет.
  6. Используйте ivar, чтобы определить, отображается ли клавиатура на экране, поскольку уведомления о клавиатуре отправляются каждый раз, когда UITextField имеет UITextField даже если клавиатура уже присутствует, чтобы избежать сокращения UIScrollView когда она уже сжата

Следует отметить, что UIKeyboardWillShowNotification будет срабатывать, даже если клавиатура уже находится на экране, когда вы UITextField другой UITextField . Я позаботился об этом, используя ivar, чтобы избежать изменения размера UIScrollView когда клавиатура уже находится на экране. Неожиданное изменение размера UIScrollView когда клавиатура уже там, будет катастрофической!

Надеюсь, что этот код избавит некоторых из вас от головной боли.

На самом деле лучше всего использовать реализацию Apple, как это предусмотрено в документах . Однако код, который они предоставляют, неисправен. Замените часть, найденную в keyboardWasShown: чуть ниже комментариев к следующему:

 NSDictionary* info = [aNotification userInfo]; CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view]; CGSize kbSize =keyPadFrame.size; CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview]; CGRect aRect = self.view.bounds; aRect.size.height -= (kbSize.height); CGPoint origin = activeRect.origin; origin.y -= backScrollView.contentOffset.y; if (!CGRectContainsPoint(aRect, origin)) { CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height)); [backScrollView setContentOffset:scrollPoint animated:YES]; } 

Проблемы с кодом Apple следующие: (1) Они всегда вычисляют, находится ли точка в кадре представления, но это ScrollView , поэтому она может уже прокручиваться, и вам нужно учитывать это смещение:

 origin.y -= scrollView.contentOffset.y 

(2) Они сдвигают contentOffset на высоту клавиатуры, но мы хотим наоборот (мы хотим сдвинуть contentOffset по высоте, которая видна на экране, а не в том, что нет):

 activeField.frame.origin.y-(aRect.size.height) 

В textFieldDidBeginEditting и в textFieldDidEndEditing вызовите функцию [self animateTextField:textField up:YES] следующим образом:

 -(void)textFieldDidBeginEditing:(UITextField *)textField { [self animateTextField:textField up:YES]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self animateTextField:textField up:NO]; } -(void)animateTextField:(UITextField*)textField up:(BOOL)up { const int movementDistance = -130; // tweak as needed const float movementDuration = 0.3f; // tweak as needed int movement = (up ? movementDistance : -movementDistance); [UIView beginAnimations: @"animateTextField" context: nil]; [UIView setAnimationBeginsFromCurrentState: YES]; [UIView setAnimationDuration: movementDuration]; self.view.frame = CGRectOffset(self.view.frame, 0, movement); [UIView commitAnimations]; } 

Надеюсь, этот код вам поможет.

В Swift 2

 func animateTextField(textField: UITextField, up: Bool) { let movementDistance:CGFloat = -130 let movementDuration: Double = 0.3 var movement:CGFloat = 0 if up { movement = movementDistance } else { movement = -movementDistance } UIView.beginAnimations("animateTextField", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration) self.view.frame = CGRectOffset(self.view.frame, 0, movement) UIView.commitAnimations() } func textFieldDidBeginEditing(textField: UITextField) { self.animateTextField(textField, up:true) } func textFieldDidEndEditing(textField: UITextField) { self.animateTextField(textField, up:false) } 

SWIFT 3

  func animateTextField(textField: UITextField, up: Bool) { let movementDistance:CGFloat = -130 let movementDuration: Double = 0.3 var movement:CGFloat = 0 if up { movement = movementDistance } else { movement = -movementDistance } UIView.beginAnimations("animateTextField", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration) self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement) UIView.commitAnimations() } func textFieldDidBeginEditing(textField: UITextField) { self.animateTextField(textField: textField, up:true) } func textFieldDidEndEditing(textField: UITextField) { self.animateTextField(textField: textField, up:false) } 

Просто используя TextFields:

1a) Использование Interface Builder : выберите All TextFields => Edit => Embed In => ScrollView

1b) Встраивание текстовых полей вручную в UIScrollView с именем scrollView

2) Установить UITextFieldDelegate

3) Установите каждый textField.delegate = self; (или сделать соединения в Interface Builder )

4) Копировать / Вставить:

 - (void)textFieldDidBeginEditing:(UITextField *)textField { CGPoint scrollPoint = CGPointMake(0, textField.frame.origin.y); [scrollView setContentOffset:scrollPoint animated:YES]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [scrollView setContentOffset:CGPointZero animated:YES]; } 

Для универсального решения здесь был мой подход к реализации IQKeyboardManager .

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

Шаг 1: – Добавлены глобальные уведомления UITextField , UITextView и UIKeyboard в одноэлементном classе. Я называю это IQKeyboardManager .

Шаг 2: – Если найдено UIKeyboardWillShowNotification , UITextFieldTextDidBeginEditingNotification или UITextViewTextDidBeginEditingNotification уведомления, я пытаюсь получить экземпляр topMostViewController из иерархии UIWindow.rootViewController . Чтобы правильно UITextField / UITextView на нем, необходимо скорректировать рамку topMostViewController.view .

Шаг 3: – Я вычислил ожидаемое расстояние перемещения topMostViewController.view отношении первого UITextField / UITextView .

Шаг 4: – Я переместил topMostViewController.view.frame вверх / вниз в соответствии с ожидаемым расстоянием перемещения.

Шаг 5: – Если найдено UIKeyboardWillHideNotification , UITextFieldTextDidEndEditingNotification или уведомление UITextViewTextDidEndEditingNotification , я снова попытаюсь получить экземпляр topMostViewController из иерархии UIWindow.rootViewController .

Шаг 6: – Я вычислил нарушенное расстояние topMostViewController.view которое необходимо восстановить в исходное положение.

Шаг7: – Я восстановил topMostViewController.view.frame вниз в соответствии с нарушенным расстоянием.

Шаг 8: – Я создал экземпляр экземпляра singleton IQKeyboardManager для загрузки приложения, поэтому каждый UITextField / UITextView в приложении будет автоматически настраиваться в соответствии с ожидаемым расстоянием перемещения.

Это все, что я делаю для IQKeyboardManager с NO LINE OF CODE ! нужно только перетащить связанный исходный файл в проект. IQKeyboardManager также поддерживает ориентацию устройств , автоматическое управление UIToolbar , KeybkeyboardDistanceFromTextField и многое другое, чем вы думаете.

Я собрал универсальный, UICollectionView UIScrollView , UITableView и даже подclass UICollectionView который заботится о перемещении всех текстовых полей в нем с клавиатуры.

Когда клавиатура вот-вот появится, подclass найдет подзаголовок, который должен быть отредактирован, и отрегулируйте его смещение кадра и содержимого, чтобы убедиться, что вид виден, с анимацией, соответствующей всплывающей подсказке клавиатуры. Когда клавиатура исчезает, она восстанавливает прежний размер.

Он должен работать в основном с любой установкой, либо с интерфейсом на основе UITableView , либо с одним представлением, размещенным вручную.

Здесь: решение для перемещения текстовых полей с клавиатуры

Для быстрых программистов:

Это сделает все для вас, просто поместите их в class controllerа вида View и реализуйте UITextFieldDelegate на свой controller представления и установите делегат textField для self

 textField.delegate = self // Setting delegate of your UITextField to self 

Внедрить методы обратного вызова делегата:

 func textFieldDidBeginEditing(textField: UITextField) { animateViewMoving(true, moveValue: 100) } func textFieldDidEndEditing(textField: UITextField) { animateViewMoving(false, moveValue: 100) } // Lifting the view up func animateViewMoving (up:Bool, moveValue :CGFloat){ let movementDuration:NSTimeInterval = 0.3 let movement:CGFloat = ( up ? -moveValue : moveValue) UIView.beginAnimations( "animateView", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration ) self.view.frame = CGRectOffset(self.view.frame, 0, movement) UIView.commitAnimations() } 

Есть уже много ответов, но все же ни один из вышеперечисленных решений не имел причудливого позиционирования, необходимого для «идеальной» без ошибок, обратной совместимости и без мерцания анимации. (ошибка при анимации фреймов / границ и contentOffset вместе, различные ориентации интерфейса, клавиатура с iPad-клавиатурой, …)
Позвольте мне поделиться своим решением:
(при условии, что вы настроили UIKeyboardWill(Show|Hide)Notification )

 // Called when UIKeyboardWillShowNotification is sent - (void)keyboardWillShow:(NSNotification*)notification { // if we have no view or are not visible in any window, we don't care if (!self.isViewLoaded || !self.view.window) { return; } NSDictionary *userInfo = [notification userInfo]; CGRect keyboardFrameInWindow; [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow]; // the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil]; CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView); UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0); // this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary. [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]]; [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]]; _scrollView.contentInset = newContentInsets; _scrollView.scrollIndicatorInsets = newContentInsets; /* * Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element * that should be visible, eg a purchase button below an amount text field * it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields */ if (_focusedControl) { CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view. CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.origin.y - _scrollView.contentOffset.y; CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height; // this is the visible part of the scroll view that is not hidden by the keyboard CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height; if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question // scroll up until the control is in place CGPoint newContentOffset = _scrollView.contentOffset; newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight); // make sure we don't set an impossible offset caused by the "nice visual offset" // if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight); [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code } else if (controlFrameInScrollView.origin.y < _scrollView.contentOffset.y) { // if the control is not fully visible, make it so (useful if the user taps on a partially visible input field CGPoint newContentOffset = _scrollView.contentOffset; newContentOffset.y = controlFrameInScrollView.origin.y; [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code } } [UIView commitAnimations]; } // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillHide:(NSNotification*)notification { // if we have no view or are not visible in any window, we don't care if (!self.isViewLoaded || !self.view.window) { return; } NSDictionary *userInfo = notification.userInfo; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]]; [UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]]; // undo all that keyboardWillShow-magic // the scroll view will adjust its contentOffset apropriately _scrollView.contentInset = UIEdgeInsetsZero; _scrollView.scrollIndicatorInsets = UIEdgeInsetsZero; [UIView commitAnimations]; } 

Shiun сказал: «Как оказалось, я считаю, что UIScrollView фактически неявно выводит текущий отредактированный UITextField в видимое окно неявно». Это похоже на iOS 3.1.3, но не на 3.2, 4.0 или 4.1. Мне нужно было добавить явный scrollRectToVisible, чтобы сделать UITextField видимым на iOS> = 3.2.

В этом документе описывается решение этой проблемы. Посмотрите исходный код в разделе «Перемещение содержимого, находящегося под клавиатурой». Это довольно просто.

EDIT: Заметил, что в этом случае есть ошибка. Вы, вероятно, захотите прослушать UIKeyboardWillHideNotification вместо UIKeyboardDidHideNotification . В противном случае прокрутка позади клавиатуры будет обрезана на время анимации закрытия клавиатуры.

Следует учитывать, хотите ли вы когда-либо использовать UITextField самостоятельно. Я не сталкивался с любыми хорошо разработанными приложениями для iPhone, которые фактически используют UITextFields вне UITableViewCells .

Это будет какая-то дополнительная работа, но я рекомендую вам реализовать все представления ввода данных в виде таблиц. Добавьте UITextView в UITableViewCells .

Было найдено самое простое решение

 - (void)textFieldDidBeginEditing:(UITextField *)textField { [self animateTextField: textField up: YES]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self animateTextField: textField up: NO]; } - (void) animateTextField: (UITextField*) textField up: (BOOL) up { const int movementDistance = 80; // tweak as needed const float movementDuration = 0.3f; // tweak as needed int movement = (up ? -movementDistance : movementDistance); [UIView beginAnimations: @"anim" context: nil]; [UIView setAnimationBeginsFromCurrentState: YES]; [UIView setAnimationDuration: movementDuration]; self.view.frame = CGRectOffset(self.view.frame, 0, movement); [UIView commitAnimations]; } 

Little fix that works for many UITextFields

 #pragma mark UIKeyboard handling #define kMin 150 -(void)textFieldDidBeginEditing:(UITextField *)sender { if (currTextField) { [currTextField release]; } currTextField = [sender retain]; //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) { [self setViewMovedUp:YES]; } } //method to move the view up/down whenever the keyboard is shown/dismissed -(void)setViewMovedUp:(BOOL)movedUp { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; // if you want to slide up the view CGRect rect = self.view.frame; if (movedUp) { // 1. move the view's origin up so that the text field that will be hidden come above the keyboard // 2. increase the size of the view so that the area behind the keyboard is covered up. rect.origin.y = kMin - currTextField.frame.origin.y ; } else { // revert back to the normal state. rect.origin.y = 0; } self.view.frame = rect; [UIView commitAnimations]; } - (void)keyboardWillShow:(NSNotification *)notif { //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin) { [self setViewMovedUp:YES]; } else if (![currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y < kMin) { [self setViewMovedUp:NO]; } } - (void)keyboardWillHide:(NSNotification *)notif { //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately if (self.view.frame.origin.y < 0 ) { [self setViewMovedUp:NO]; } } - (void)viewWillAppear:(BOOL)animated { // register for keyboard notifications [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:self.view.window]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:self.view.window]; } - (void)viewWillDisappear:(BOOL)animated { // unregister for keyboard notifications while not visible. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; } 

RPDP’s code successfully moves the text field out of the way of the keyboard. But when you scroll to the top after using and dismissing the keyboard, the top has been scrolled up out of the view. This is true for the Simulator and the device. To read the content at the top of that view, one has to reload the view.

Isn’t his following code supposed to bring the view back down?

 else { // revert back to the normal state. rect.origin.y += kOFFSET_FOR_KEYBOARD; rect.size.height -= kOFFSET_FOR_KEYBOARD; } 

I’m not sure if moving the view up is the correct approach, I did it in a differente way, resizing the UIScrollView. I explained it in details on a little article

To bring back to original view state, add:

 -(void)textFieldDidEndEditing:(UITextField *)sender { //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y < 0) { [self setViewMovedUp:NO]; } } 

There so many solutions, but I’ve spend some hours before it start works. So, I put this code here (just paste to the project, any modifications needn’t):

 @interface RegistrationViewController : UIViewController { UITextField* activeField; UIScrollView *scrollView; } @end - (void)viewDidLoad { [super viewDidLoad]; scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame]; //scrool view must be under main view - swap it UIView* natView = self.view; [self setView:scrollView]; [self.view addSubview:natView]; CGSize scrollViewContentSize = self.view.frame.size; [scrollView setContentSize:scrollViewContentSize]; [self registerForKeyboardNotifications]; } - (void)viewDidUnload { activeField = nil; scrollView = nil; [self unregisterForKeyboardNotifications]; [super viewDidUnload]; } - (void)registerForKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil]; } -(void)unregisterForKeyboardNotifications { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; // unregister for keyboard notifications while not visible. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } - (void)keyboardWillShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; CGRect frame = self.view.frame; frame.size.height -= kbSize.height; CGPoint fOrigin = activeField.frame.origin; fOrigin.y -= scrollView.contentOffset.y; fOrigin.y += activeField.frame.size.height; if (!CGRectContainsPoint(frame, fOrigin) ) { CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y + activeField.frame.size.height - frame.size.height); [scrollView setContentOffset:scrollPoint animated:YES]; } } - (void)keyboardWillBeHidden:(NSNotification*)aNotification { [scrollView setContentOffset:CGPointZero animated:YES]; } - (void)textFieldDidBeginEditing:(UITextField *)textField { activeField = textField; } - (void)textFieldDidEndEditing:(UITextField *)textField { activeField = nil; } -(BOOL) textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return YES; } 

PS: I hope the code help somebody make desired effect quickly. (Xcode 4.5)

try this short trick…

  - (void)textFieldDidBeginEditing:(UITextField *)textField { [self animateTextField: textField up: YES]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self animateTextField: textField up: NO]; } - (void) animateTextField: (UITextField*) textField up: (BOOL) up { const int movementDistance = textField.frame.origin.y / 2; // tweak as needed const float movementDuration = 0.3f; // tweak as needed int movement = (up ? -movementDistance : movementDistance); [UIView beginAnimations: @"anim" context: nil]; [UIView setAnimationBeginsFromCurrentState: YES]; [UIView setAnimationDuration: movementDuration]; self.view.frame = CGRectOffset(self.view.frame, 0, movement); [UIView commitAnimations]; } 

Happy coding :)….

@user271753

To get your view back to original add:

 -(BOOL)textFieldShouldReturn:(UITextField *)textField{ [textField resignFirstResponder]; [self setViewMovedUp:NO]; return YES; } 

It doesn’t require a scroll view to be able to move the view frame. You can change the frame of a viewcontroller's view so that the entire view moves up just enough to put the firstresponder text field above the keyboard. When I ran into this problem I created a subclass of UIViewController that does this. It observes for the keyboard will appear notification and finds the first responder subview and (if needed) it animates the main view upward just enough so that the first responder is above the keyboard. When the keyboard hides, it animates the view back where it was.

To use this subclass make your custom view controller a subclass of GMKeyboardVC and it inherits this feature (just be sure if you implement viewWillAppear and viewWillDisappear they must call super). The class is on github .

As per the docs , as of iOS 3.0, the UITableViewController class automatically resizes and repositions its table view when there is in-line editing of text fields. I think it’s not sufficient to put the text field inside a UITableViewCell as some have indicated.

Из документов :

A table view controller supports inline editing of table view rows; if, for example, rows have embedded text fields in editing mode, it scrolls the row being edited above the virtual keyboard that is displayed.

Here is the hack solution I came up with for a specific layout. This solution is similar to Matt Gallagher solution in that is scrolls a section into view. I am still new to iPhone development, and am not familiar with how the layouts work. Thus, this hack.

My implementation needed to support scrolling when clicking in a field, and also scrolling when the user selects next on the keyboard.

I had a UIView with a height of 775. The controls are spread out basically in groups of 3 over a large space. I ended up with the following IB layout.

 UIView -> UIScrollView -> [UI Components] 

Here comes the hack

I set the UIScrollView height to 500 units larger then the actual layout (1250). I then created an array with the absolute positions I need to scroll to, and a simple function to get them based on the IB Tag number.

 static NSInteger stepRange[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410 }; NSInteger getScrollPos(NSInteger i) { if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) { return 0 ; return stepRange[i] ; } 

Now all you need to do is use the following two lines of code in textFieldDidBeginEditing and textFieldShouldReturn (the latter one if you are creating a next field navigation)

 CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ; [self.scrollView setContentOffset:point animated:YES] ; 

An example.

 - (void) textFieldDidBeginEditing:(UITextField *)textField { CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ; [self.scrollView setContentOffset:point animated:YES] ; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { NSInteger nextTag = textField.tag + 1; UIResponder* nextResponder = [textField.superview viewWithTag:nextTag]; if (nextResponder) { [nextResponder becomeFirstResponder]; CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ; [self.scrollView setContentOffset:point animated:YES] ; } else{ [textField resignFirstResponder]; } return YES ; } 

This method does not ‘scroll back’ as other methods do. This was not a requirement. Again this was for a fairly ‘tall’ UIView, and I did not have days to learn the internal layout engines.

Here I found the simplest solution to handle keypad.

You need to just copy-paste below sample code and change your textfield or any view which you want to move up.

Шаг 1

Just copy-paste below two method in your controller

 - (void)registerForKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil]; } - (void)deregisterFromKeyboardNotifications { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } 

Шаг 2

register & deregister Keypad Notifications in viewWillAppear and viewWillDisappear methods respectively.

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self registerForKeyboardNotifications]; } - (void)viewWillDisappear:(BOOL)animated { [self deregisterFromKeyboardNotifications]; [super viewWillDisappear:animated]; } 

Шаг 3

Here comes the soul part, Just replace your textfield, and change height how much you want to move upside.

 - (void)keyboardWasShown:(NSNotification *)notification { NSDictionary* info = [notification userInfo]; CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; //you need replace your textfield instance here CGPoint textFieldOrigin = self.tokenForPlaceField.frame.origin; CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height; CGRect visibleRect = self.view.frame; visibleRect.size.height -= currentKeyboardSize.height; if (!CGRectContainsPoint(visibleRect, textFieldOrigin)) { //you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height [self.scrollView setContentOffset:scrollPoint animated:YES]; } } - (void)keyboardWillBeHidden:(NSNotification *)notification { [self.scrollView setContentOffset:CGPointZero animated:YES]; } 

Reference : well, Please appreciate this guy , who shared this beautiful code snip, clean solution.

Hope this would be surly helpful someone out there.

Been searching for a good tutorial for beginners on the subject, found the best tutorial here .

In the MIScrollView.h example at the bottom of the tutorial be sure to put a space at

 @property (nonatomic, retain) id backgroundTapDelegate; 

as you see.

Use this third party you don’t need to write even one line

https://github.com/hackiftekhar/IQKeyboardManager

download project and drag and drop IQKeyboardManager in your project. If you find any issue please read README document.

Guys really its remove headache to manage keyboard ..

Thanks and best of luck!

When UITextField is in a UITableViewCell scrolling should be setup automatically.

If it is not it is probably because of incorrect code/setup of the tableview.

For example when i reloaded my long table with one UITextField at the bottom as follows,

 -(void) viewWillAppear:(BOOL)animated { [self.tableview reloadData]; } 

then my textfield at the bottom was obscured by the keyboard which appeared when I clicked inside the textfield.

To fix this I had to do this –

 -(void) viewWillAppear:(BOOL)animated { //add the following line to fix issue [super viewWillAppear:animated]; [self.tableview reloadData]; } 

Swift 4 .

You Can Easily Move Up And Down UITextField Or UIView With UIKeyBoard With Animation введите описание изображения здесь

 import UIKit class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet var textField: UITextField! @IBOutlet var chatView: UIView! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil) } override func touchesBegan(_ touches: Set, with event: UIEvent?) { textField.resignFirstResponder() } @objc func keyboardWillChange(notification: NSNotification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y print("deltaY",deltaY) UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.chatView.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField },completion: nil) } func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } } 

Note : this answer assumes your textField is in a scrollView.

I prefer to deal with this using scrollContentInset and scrollContentOffset instead of messing with the frames of my view.

First let’s listen for the keyboard notifications

 //call this from viewWillAppear -(void)addKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } //call this from viewWillDisappear -(void)removeKeyboardNotifications{ [[NSNotificationCenter default Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } 

Next step is to keep a property that represents the current first responder (UITextfield/ UITextVIew that currently has the keyboard).

We use the delegate methods to set this property. If you’re using another component, you will need something similar.

Note that for textfield we set it in didBeginEditing and for textView in shouldBeginEditing. This is because textViewDidBeginEditing gets called after UIKeyboardWillShowNotification for some reason.

 -(BOOL)textViewShouldBeginEditing:(UITextView * )textView{ self.currentFirstResponder = textView; return YES; } -(void)textFieldDidBeginEditing:(UITextField *)textField{ self.currentFirstResponder = textField; } 

Finally, here’s the magic

 - (void)keyboardWillShow:(NSNotification*)aNotification{ NSDictionary* info = [aNotification userInfo]; CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; /*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/ if(self.currentFirstResponder){ //keyboard origin in currentFirstResponderFrame CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.origin fromView:nil]; float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y); //only scroll the scrollview if keyboard overlays the first responder if(spaceBetweenFirstResponderAndKeyboard>0){ //if i call setContentOffset:animate:YES it behaves differently, not sure why [UIView animateWithDuration:0.25 animations:^{ [self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)]; }]; } } //set bottom inset to the keyboard height so you can still scroll the whole content UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0); _scrollView.contentInset = contentInsets; _scrollView.scrollIndicatorInsets = contentInsets; } - (void)keyboardWillHide:(NSNotification*)aNotification{ UIEdgeInsets contentInsets = UIEdgeInsetsZero; _scrollView.contentInset = contentInsets; _scrollView.scrollIndicatorInsets = contentInsets; } 

This is the solution using Swift.

 import UIKit class ExampleViewController: UIViewController, UITextFieldDelegate { @IBOutlet var scrollView: UIScrollView! @IBOutlet var textField1: UITextField! @IBOutlet var textField2: UITextField! @IBOutlet var textField3: UITextField! @IBOutlet var textField4: UITextField! @IBOutlet var textField5: UITextField! var activeTextField: UITextField! // MARK: - View override func viewDidLoad() { super.viewDidLoad() self.textField1.delegate = self self.textField2.delegate = self self.textField3.delegate = self self.textField4.delegate = self self.textField5.delegate = self } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) self.registerForKeyboardNotifications() } override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) self.unregisterFromKeyboardNotifications() } // MARK: - Keyboard // Call this method somewhere in your view controller setup code. func registerForKeyboardNotifications() { let center: NSNotificationCenter = NSNotificationCenter.defaultCenter() center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil) center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil) } func unregisterFromKeyboardNotifications () { let center: NSNotificationCenter = NSNotificationCenter.defaultCenter() center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil) center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) } // Called when the UIKeyboardDidShowNotification is sent. func keyboardWasShown (notification: NSNotification) { let info : NSDictionary = notification.userInfo! let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; // If active text field is hidden by keyboard, scroll it so it's visible // Your app might not need or want this behavior. var aRect = self.view.frame aRect.size.height -= kbSize.height; if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) { self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true) } } // Called when the UIKeyboardWillHideNotification is sent func keyboardWillBeHidden (notification: NSNotification) { let contentInsets = UIEdgeInsetsZero; scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; } // MARK: - Text Field func textFieldDidBeginEditing(textField: UITextField) { self.activeTextField = textField } func textFieldDidEndEditing(textField: UITextField) { self.activeTextField = nil } } 
  • Может ли iPhone приложение блокировать телефонные звонки?
  • Возможно открытие всплывающих ссылок в UIWebView?
  • Как использовать метод prepareForReuse
  • Msgstr "wait_fences: не удалось получить ответ: 10004003"?
  • UIPopoverPresentationController на iOS 8 iPhone
  • UIImage от CALayer - iPhone SDK
  • Одновременные распознаватели жестов в Iphone SDK
  • Измените первый символ в каждом слове строки на верхний регистр.
  • Как использовать performSelector: withObject: afterDelay: с примитивными типами в cocoa?
  • Получение времени, прошедшего в Objective-C
  • UISlider для управления AVAudioPlayer
  • Interesting Posts

    Как использовать workbook.saveas с автоматической перезаписью

    Добавление Google Cloud Messagin (GCM) для Android – Процесс регистрации

    Зачем использовать Fragment # setRetainInstance (boolean)?

    Как извлечь ISO на Linux без доступа root

    json.stringify не обрабатывает методы объекта

    Недействительный BOOT.INI (двойной загрузочный XP с 7)

    JSON и экранирующие символы

    Что такое модификатор доступа по умолчанию в Java?

    Как вы явно устанавливаете новое свойство в `window` в TypeScript?

    Ноутбук просит пароль (который я никогда не устанавливал), даже если без жесткого диска

    Возвращаемое значение из вызываемой функции в сценарии оболочки

    Табличное представление Javafx не показывает данные во всех столбцах

    Почему super.super.method (); не разрешено в Java?

    Что такое самодокументирующий код и может ли он заменить хорошо документированный код?

    Excel: как внутренне хранить числовое значение в ячейке, но сделать ее по-разному (например, алфавитные имена)?

    Давайте будем гением компьютера.