Как я могу заставить UITextField двигаться вверх при наличии клавиатуры - при начале редактирования? - PullRequest
1644 голосов
/ 14 июля 2009

С iOS SDK:

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

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

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

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

Мне нужны и UIView, и UIScrollView? Один входит в другой?

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

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

Примечание: 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
}

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

Ответы [ 91 ]

4 голосов
/ 03 декабря 2012

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

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
     if(textField == answer)
    {   
         CGPoint cPoint = textField.frame.origin;
         [scrollView setContentOffset:CGPointMake(0, cPoint.y - 100) animated:YES];
    }
}

Примечание: Вы должны изменить значение cPoint.y - 100 в соответствии с вашим мнением.

4 голосов
/ 11 августа 2014

https://github.com/michaeltyson/TPKeyboardAvoiding скачайте этот файл и добавьте пользовательский класс, так как в вашем табличном представлении он будет управлять всеми вещами, поскольку вам не нужно ничего делать. у него есть много опций, вы можете проверить его и для других, это все, что вам нужно, чтобы избежать клавиатуры

4 голосов
/ 06 августа 2014

Есть много ответов, говорящих о подходе. Я использовал тот же подход, но реализация не очень хорошая.

Вот базовая идея . Я внес изменения в метод клавиатурыWasShown.

{
// Obtain keyboard Info
NSDictionary* info = [notification userInfo];
CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];

// Obtain ScrollView Info w.r.t. top View
CGRect scrollViewRect = [self.view convertRect:self.scrollView.frame fromView:nil];

// Depending upon your screen Ui, Scroll View's bottom edge might be at some offset from screen's bottom
// Calculate the exact offset
int scrollViewBottomOffset = self.view.frame.size.height - (scrollViewRect.origin.y + scrollViewRect.size.height);
int heightToBeAdjusted = keyboardRect.size.height - scrollViewBottomOffset;


// We may also need to consider the Insets if already present with ScrollView. Let's keep it simple for now
// But we should store these, so that we can restore the Insets when Keyboard is gone
// origInsets = self.scrollView.contentInset;

// Set the new Insets for ScrollView
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, heightToBeAdjusted, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;

// Visible frame (not overlapped by Keyboard)
CGRect visibleFrame = self.view.frame;
visibleFrame.size.height -= keyboardRect.size.height;

// Get the Rect for Textfield w.r.t self.view
CGRect activeFieldFrame = self.activeField.frame;
activeFieldFrame = [self.view convertRect:activeFieldFrame fromView:self.scrollView];

// Check if the TextField is Visible or not
if (!CGRectContainsRect(visibleFrame, activeFieldFrame) ) {
    // Scroll to make it visible but for scrolling use the activeField frame w.r.t. to scroll View
    [self.scrollView scrollRectToVisible:self.activeField.frame animated:YES];
}

}

И добавьте этот метод для инициализации activeField

- (IBAction)textFieldDidBeginEditing:(UITextField *)sender
{
self.activeField = sender;
}
4 голосов
/ 01 августа 2017

Я знаю, что уже слишком поздно, но я хотел бы поделиться с будущими посетителями, особенно о том, как это сделать. Было опубликовано много хороших методов, но мне не понравилось, как интерфейс стал совершенно плохим. Есть простой метод, который состоит из двух частей: -

  1. Добавьте TextField и, что бы вы ни хотели, чтобы он перемещался над клавиатурой во время редактирования, в представление, чтобы они стали дочерними элементами представления. И тогда будет легко поддерживать внешний вид и не повлиять на интерфейс.
  2. Используйте отличный инструмент CGAffineTransform(TranslationX: x, TranslationY: y) , чтобы переместить созданный вид над клавиатурой.

Я знаю, что это кажется очень простым, но действительно эффективным и аккуратным. enter image description here

4 голосов
/ 22 марта 2016

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

func keyboardShown(notification: NSNotification) {
    let info  = notification.userInfo!
    let value: AnyObject = info[UIKeyboardFrameEndUserInfoKey]!

    let rawFrame = value.CGRectValue
    let keyboardFrame = view.convertRect(rawFrame, fromView: nil)

    let screenHeight = UIScreen.mainScreen().bounds.size.height;
    let Ylimit = screenHeight - keyboardFrame.size.height
    let textboxOriginInSuperview:CGPoint = self.view.convertPoint(CGPointZero, fromCoordinateSpace: lastTextField!)

    self.keyboardHeight = (textboxOriginInSuperview.y+self.lastTextField!.frame.size.height) - Ylimit

    if(self.keyboardHeight>0){
        self.animateViewMoving(true, moveValue: keyboardHeight!)
    }else{
        keyboardHeight=0
    }
}

keyBoardHeight - это смещение.

3 голосов
/ 22 января 2015

Простое решение, расширяющее UIViewController

https://github.com/damienromito/VisibleFormViewController

enter image description here

3 голосов
/ 16 ноября 2013

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

MessageComposerView

http://www.thegameengine.org/wp-content/uploads/2013/11/message_composer_quad_1.jpg

Идея этого проекта состояла в том, чтобы создать нечто, функционирующее подобно составному представлению iMessage AKA:

  • прилипает к верхней части клавиатуры и перемещается к нижней части экрана при отклонении клавиатуры
  • обрабатывает изменения в тексте
  • обрабатывает повороты

Чтобы изменить размер / перенастроить UIScrollView, вам нужно использовать следующий необязательный метод делегата:

- (void)messageComposerFrameDidChange:(CGRect)frame withAnimationDuration:(float)duration;

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

3 голосов
/ 02 апреля 2013

Пожалуйста, следуйте этим шагам.

1) Объявите следующую переменную в файле .h.

  {      
         CGFloat animatedDistance;
  }

2) Объявите следующие константы в файле .m.

  static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
  static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
  static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
  static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
  static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 162;

3) Используйте делегат UITextField для перемещения вверх / вниз клавиатуры.

  -(void) textFieldDidBeginEditing:(UITextField *)textField
  { 
         if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
         {
               CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
               CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];

               CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
               CGFloat numerator =
    midline - viewRect.origin.y
    - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
               CGFloat denominator =
    (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION)
    * viewRect.size.height;
               CGFloat heightFraction = numerator / denominator;

               if (heightFraction < 0.0)
               {
                     heightFraction = 0.0;
               }
               else if (heightFraction > 1.0)
               {
                     heightFraction = 1.0;
               }

               UIInterfaceOrientation orientation =
    [[UIApplication sharedApplication] statusBarOrientation];
               if (orientation == UIInterfaceOrientationPortrait)
               {
                     animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
               }
               else
               {
                     animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
               }

               CGRect viewFrame = self.view.frame;
               viewFrame.origin.y -= animatedDistance;

               [UIView beginAnimations:nil context:NULL];
               [UIView setAnimationBeginsFromCurrentState:YES];
               [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

               [self.view setFrame:viewFrame];

               [UIView commitAnimations];
       }
  }

  -(void) textFieldDidEndEditing:(UITextField *)textField
  {
       if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
       {
             CGRect viewFrame = self.view.frame;
             viewFrame.origin.y += animatedDistance;

             [UIView beginAnimations:nil context:NULL];
             [UIView setAnimationBeginsFromCurrentState:YES];
             [UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];

             [self.view setFrame:viewFrame];

             [UIView commitAnimations];
       }
 }
3 голосов
/ 17 июля 2016

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

Вот мой подход (Слегка видоизмененный путь яблока) -

// UIKeyboardDidShowNotification
- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}

// UIKeyboardWillHideNotification
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}
3 голосов
/ 06 мая 2015

Я упаковываю все в один класс. Просто вызовите эти строки кода, когда ваш viewcontroller загружен:

- (void)viewDidLoad {
    [super viewDidLoad];
    KeyboardInsetScrollView *injectView = [[KeyboardInsetScrollView alloc] init];
    [injectView injectToView:self.view withRootView:self.view];
}

Вот ссылка на пример проекта:
https://github.com/caohuuloc/KeyboardInsetScrollView

...