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

1538

С iOS SDK:

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

  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
}

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

  • 0
    Вы можете использовать анимацию в текстовом поле, чтобы текстовое поле двигалось при появлении клавиатуры
  • 6
    Проверь это. Нет проблем для вас. TPKeyboardAvoiding
Показать ещё 17 комментариев
Теги:
uitextfield
uiscrollview
uikeyboard

93 ответа

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

  • Чтобы показать 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 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];
}
  • 3
    Что значит _textField? Я скопировал его в свой код, он говорит, что _textField не объявлен.
  • 0
    Это поле, которое вы используете, чтобы сказать «когда пользователь редактирует здесь, представление должно сдвинуться вверх» или что-то в этом роде ... Однако вы можете удалить это, если, если вам нужно больше полей.
Показать ещё 23 комментария
440

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

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

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

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

3) Здесь catch: Когда я впервые это сделал, я решил, что мне нужно будет получить CGRect отредактированного текстового поля и вызвать метод UIScrollView's scrollRecToVisible. Я применил метод UITextFieldDelegate textFieldDidBeginEditing с вызовом метода scrollRecToVisible. Это действительно со странным побочным эффектом, что прокрутка привяжет UITextField к позиции. В течение долгого времени я не мог понять, что это было. Затем я прокомментировал метод textFieldDidBeginEditing Delegate, и все это работает!! (???). Как оказалось, я полагаю, что UIScrollView фактически неявно выводит текущий отредактированный 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;
}
  • Зарегистрируйтесь для уведомлений о клавиатуре на viewDidLoad
  • Отменить регистрацию клавиатурных nofitications на viewDidUnload
  • Убедитесь, что contentSize установлен и больше, чем ваш UIScrollView на viewDidLoad
  • Сжатие UIScrollView при наличии клавиатуры
  • Верните назад UIScrollView, когда клавиатура уходит.
  • Используйте ivar, чтобы определить, отображается ли клавиатура на экране, поскольку уведомления о клавиатуре отправляются каждый раз, когда вкладка UITextField имеет вкладку, даже если клавиатура уже присутствует, чтобы избежать сокращения UIScrollView, когда она уже сжата

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

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

  • 3
    Отлично, но две проблемы: 1. UIKeyboardBoundsUserInfoKey устарела. 2. keyboardSize находится в «координатах экрана», поэтому ваши вычисления в viewFrame завершатся неудачно, если кадр будет повернут или масштабирован.
  • 21
    @Martin Wickman - Использовать CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; вместо устаревшего UIKeyboardBoundsUserInfoKey
Показать ещё 18 комментариев
278

На самом деле лучше всего использовать реализацию 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)
  • 0
    Не будет ли лучшим решением отрегулировать размер прокрутки, чтобы его высота соответствовала верхней части клавиатуры?
  • 0
    Это не работает для меня, мой взгляд прокручивается вниз, а не вверх, он просто полностью прячется за моей клавиатурой.
Показать ещё 16 комментариев
231

В 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)
    }
  • 1
    почему бы не использовать [UIView animateWithDuration: animations:^{ }]; ?
  • 0
    Просто потрясающий человек ...... просто установите расстояние для движения ...... и тогда вы раскачиваетесь.
Показать ещё 17 комментариев
127

Просто используя 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];
}
  • 8
    Но он также перемещается вверх по виду, когда textField уже виден.
  • 1
    Необходимо изменить CGPointMake(0, textField.frame.origin.y); в CGPointMake(0, textField.frame.origin.y + scrollView.contentInset.top);
Показать ещё 1 комментарий
116

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

Изображение 5125

Шаг1: -. Добавлены глобальные уведомления UITextField, UITextView и UIKeyboard в одноэлементном классе. Я называю это 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 сделали для вас НЕТ ЛИНИИ КОДА! нужно только перетащить связанный исходный файл в проект. IQKeyboardManager также поддерживают Ориентация устройства, Автоматическое управление UIToolbar, KeybkeyboardDistanceFromTextField и многое другое. больше, чем вы думаете.

  • 0
    Добавить каталог IQKeyBoardManagerSwift в мой проект и не работать. Не могу включить, потому что его не распознают в AppDelegate ...
  • 1
    это похоже на фишинг, фактическое решение не показано, но вместо этого мы видим рекламу этого аккаунта на GitHub.
96

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

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

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

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

  • 0
    Это оно! Это лучшее, самое эффективное и идеальное решение! Это также обрабатывает вращения правильно для представлений прокрутки. При вращении убедитесь, что вы автоматически меняете размеры по вертикали, но не ставьте якорь внизу. Я добавил UITextView в представление прокрутки в моем случае. Спасибо, связки!
  • 0
    Очень хорошая работа! Конечно, мне лень использовать ваше решение вместо DIY, но мой босс счастливее, так что да! Даже если кто-то хочет сделать это сам, мне нравится ваш подход к подклассам вместо добавления кода для каждого контроллера. Я был в шоке, iOS не делает этого по умолчанию, как это делал Android - опять же, я нахожу много недостатков в iOS и MacOS :(
Показать ещё 2 комментария
81

Для Swift Программисты:

Это сделает все для вас, просто поместите их в свой класс контроллера вида и реализуйте UITextFieldDelegate в свой контроллер представления и установите делегат 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()
}
  • 2
    SwiftLint не понравился self.view.frame = CGRectOffset(self.view.frame, 0, movement) поэтому я изменил эту строку на self.view.frame.offsetInPlace(dx: 0, dy: movement)
  • 1
    Swift 4 изменить self.view.frame = CGRectOffset (self.view.frame, 0, движение) на self.view.frame.offsetBy (dx: 0, dy: движение)
63

Есть уже много ответов, но все же ни один из вышеперечисленных решений не обладал фантастическим позиционированием, необходимым для "идеальной" без ошибок, обратной совместимости и без мерцания анимации. (ошибка при анимации кадров/границ и 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, e.g. 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];
}
  • 0
    Большие улучшения ответа @Shiun. Но после того, как клавиатура пропала, вид не возвращается в 1-е положение. Это все еще отличная работа :)
  • 2
    Спасибо, это лучшее решение для меня в 2017 году. Заметьте, что вам не нужно самостоятельно отслеживать focusControl, вы можете определить это с помощью UIApplication.shared.sendAction(...) . Вот версия Swift 3 вашего ответа (willHide часть минус), с sendAction внедрено: gist.github.com/xaphod/7aab1302004f6e933593a11ad8f5a72d
Показать ещё 2 комментария
58

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

46

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

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

  • 1
    Одно из моих приложений должно позволять пользователям добавлять заметки произвольной формы, так что да, иногда полезно использовать UITextField.
  • 1
    Я согласен с этим методом. Ноль работы или код таким образом. Даже если вам нужна заметка свободной формы, вы все равно можете использовать ячейку таблицы
Показать ещё 2 комментария
45

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

РЕДАКТИРОВАТЬ: В этом примере заметен сбой. Вероятно, вы захотите слушать UIKeyboardWillHideNotification вместо UIKeyboardDidHideNotification. В противном случае прокрутка позади клавиатуры будет обрезана на время анимации закрытия клавиатуры.

32

Небольшое исправление, которое работает для многих 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 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]; 
}
  • 0
    у меня не сработало
  • 0
    rect.origin.y=+currTextField.frame.origin.y работает нормально спасибо
Показать ещё 1 комментарий
31

Самое быстрое найденное решение

- (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];
}
  • 0
    Экран движется вверх, даже если он не внизу. то есть, если текстовое поле находится сверху, оно выходит за пределы экрана. Как контролировать этот случай?
  • 0
    @MELWIN Просто добавьте после этой строки: int movement = (up ? -movementDistance : movementDistance); if (textField.frame.origin.y < self.view.frame.size.height - keyboard.height) { movementDistance = 0 } Обратите внимание, что переменная keyboard - это CGRect клавиатуры, которая появляется, которую вы получаете, выполнив: let keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey]!.CGRectValue())!
28

Код RPDP успешно перемещает текстовое поле с клавиатуры. Но когда вы переходите к вершине после использования и отклонения клавиатуры, верхняя часть прокручивается вверх из представления. Это верно для симулятора и устройства. Чтобы прочитать содержимое в верхней части этого представления, нужно перезагрузить представление.

Разве его следующий код не должен возвращать представление?

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

Я не уверен, что если переместить представление вверх, это правильный подход, я сделал это другим способом, изменив размер UIScrollView. Я подробно объяснил это в небольшом статье

20

Чтобы вернуться в исходное состояние просмотра, добавьте:

-(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];
    }
}
19

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

@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
    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;
}

P.S: Я надеюсь, что код поможет кому-то сделать желаемый эффект быстро. (Xcode 4.5)

  • 0
    Привет Hotjard, я получаю EXE_BAD_ACCESS в [self.view addSubview: natView];
18

Попробуйте этот короткий трюк.

- (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];
}
18

@user271753

Чтобы вернуться к исходному, добавьте:

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

Для перемещения рамки просмотра не требуется просмотр прокрутки. Вы можете изменить рамку представления viewcontroller's, чтобы весь вид перемещался настолько, чтобы помещать текстовое поле firstresponder над клавиатурой. Когда я столкнулся с этой проблемой, я создал подкласс UIViewController, который делает это. Он замечает, что на клавиатуре появится уведомление и обнаружит первый ответчик subview и (при необходимости) он оживляет основной вид вверх настолько, чтобы первый ответчик находился выше клавиатуры. Когда клавиатура скрывается, она оживляет вид назад, где он был.

Чтобы использовать этот подкласс, сделайте свой пользовательский контроллер представлений подклассом GMKeyboardVC и он наследует эту функцию (просто убедитесь, что вы реализуете viewWillAppear и viewWillDisappear они должны вызвать супер). Класс находится на github.

  • 0
    Какая лицензия? Некоторые из ваших файлов имеют лицензию с открытым исходным кодом, а некоторые нет.
  • 0
    Предупреждение: этот код не подходит для проектов ARC.
Показать ещё 1 комментарий
13

Свифт 4.

Вы можете легко перемещаться вверх и вниз по UITextField или UIView с UIKeyBoard с Animation Изображение 5126

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<UITouch>, 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
    }

}
  • 0
    Хорошее простое решение.
  • 2
    Практически идеально. На iPhone X вы получаете странный разрыв между клавиатурой и текстовым полем.
12

В соответствии с документами, начиная с iOS 3.0, класс UITableViewController автоматически изменяет размеры и перетаскивает его представление таблицы при редактировании текстовых полей. Я думаю, этого недостаточно, чтобы помещать текстовое поле внутри UITableViewCell, как указывали некоторые.

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

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

  • 0
    Я нашел тот же комментарий. Да, это правда. Странно то, что он работает в одном UITabelViewController, а во втором - нет. Но я не смог найти никаких различий в моей реализации.
12

Вот решение для взлома, которое я разработал для конкретного макета. Это решение похоже на решение Мэтта Галлахера, в котором прокручивается секция. Я до сих пор не знаком с разработкой iPhone и не знаю, как работают макеты. Таким образом, этот хак.

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

У меня был UIView с высотой 775. Элементы управления распределены в основном группами по 3 на большом пространстве. Я закончил со следующей версией IB.

UIView -> UIScrollView -> [UI Components]

Вот взлом

Я установил высоту UIScrollView на 500 единиц больше, чем фактический макет (1250). Затем я создал массив с абсолютными позициями, которые мне нужно прокрутить, и простую функцию для их получения на основе номера метки IB.

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] ;
}

Теперь все, что вам нужно сделать, это использовать следующие две строки кода в textFieldDidBeginEditing и textFieldShouldReturn (последний, если вы создаете следующую навигацию по полю)

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

Пример.

- (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 ;
}

Этот метод не выполняет "прокрутку назад", как это делают другие методы. Это не было требованием. Снова это было для довольно "высокого" UIView, и у меня не было дней, чтобы изучить внутренние механизмы компоновки.

  • 0
    Этому ответу около 7 лет !!!!!! Это хороший пример «совершенно неуместного» материала, который висит на SO.
11

Здесь я нашел простейшее решение для обработки клавиатуры.

Вам нужно просто скопировать-вставить ниже пример кода и изменить текстовое поле или любое представление, которое вы хотите переместить вверх.

Шаг-1

Просто скопируйте пасту ниже двух методов в вашем контроллере

- (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

зарегистрировать и отменить регистрацию уведомлений о клавиатуре в viewWillAppear и viewWillDisappear соответственно.

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

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

Шаг-3

Здесь приходит душа, просто замените текстовое поле и измените высоту, сколько вы хотите двигаться вверх.

- (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];
}

Ссылка: хорошо, Пожалуйста, оцените этот парень, который поделился этим красивым отрывом кода, чистым решением.

Надеюсь, это было бы очень полезно кому-то там.

  • 0
    Я не думаю, что это лучшее. Я думаю, @Dheeraj VS прав: это можно сделать легко и автоматически, если это текстовое поле находится в ячейке таблицы (даже когда table.scrollable = NO). Обратите внимание : положение и размер стола должны быть разумными. Например: - если позиция y таблицы равна 100 от нижней части представления, то клавиатура высотой 300 будет перекрывать всю таблицу. - если высота таблицы = 10, а текстовое поле в ней должно быть прокручено на 100, когда клавиатура появляется, чтобы быть видимой, то это текстовое поле будет вне границы таблицы.
  • 0
    @ samthui7 Dheeraj ответ работает, только если вы используете TableViewController, а не просто просмотр таблицы. Это делает это ограничение, которое иногда не подходит.
10

Поиск хорошего учебника для новичков по теме, нашел лучший учебник здесь.

В примере MIScrollView.h внизу учебника обязательно поставьте пробел в

@property (nonatomic, retain) id backgroundTapDelegate;

как вы видите.

  • 0
    Привет savagenoob, спасибо за предоставленную ссылку и добро пожаловать в stackoverflow. Пожалуйста, постарайтесь предоставить как можно больше информации при ответе на (будущие) вопросы - простые ссылки немного хрупкие. Тем не менее, если ответ является ссылкой на хороший учебник, который может быть пропущен.
10

Когда UITextField находится в UITableViewCell, прокрутка должна автоматически настраиваться.

Если это не так, возможно, из-за неправильного кода/настройки таблицы.

Например, когда я перезагрузил свой длинный стол одним UITextField внизу следующим образом,

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

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

Чтобы исправить это, я должен был сделать это -

-(void) viewWillAppear:(BOOL)animated
{
    //add the following line to fix issue
    [super viewWillAppear:animated];
    [self.tableview reloadData];
}
  • 0
    Я запутался, для чего этот код? Когда клавиатура отображается, viewWillAppear не вызывается. И reloadData не делает reloadData строки видимыми.
9

Используйте эту третью сторону, вам не нужно писать даже одну строку

https://github.com/hackiftekhar/IQKeyboardManager

загрузить проект и перетащить IQKeyboardManager в ваш проект. Если вы обнаружили какую-либо проблему, прочитайте документ README.

Ребята действительно снимают головную боль, чтобы управлять клавиатурой.

Спасибо и удачи!

8

Это решение, использующее 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 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
    }

}
  • 0
    Правильный ответ, но у меня проблема с нулем при использовании TextField и TextView. Любая помощь?
  • 0
    @Thiha Aung, Ваши переменные IBOutlet в вашем исходном коде связаны с IB?
Показать ещё 2 комментария
8

Примечание: этот ответ предполагает, что ваш textField находится в scrollView.

Я предпочитаю иметь дело с этим, используя scrollContentInset и scrollContentOffset вместо того, чтобы возиться с рамками моего представления.

Сначала давайте прослушать уведомления о клавиатуре

//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];
}

Следующий шаг - сохранить свойство, которое представляет текущий первый ответчик (UITextfield/UITextVIew, который в настоящее время имеет клавиатуру).

Мы используем методы делегата для установки этого свойства. Если вы используете другой компонент, вам понадобится нечто подобное.

Обратите внимание, что для текстового поля мы устанавливаем его в файле doBeginEditing и для textView в shouldBeginEditing. Это связано с тем, что textViewDidBeginEditing вызывается после UIKeyboardWillShowNotification по какой-то причине.

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

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    self.currentFirstResponder = textField;
}

Наконец, здесь волшебство

- (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;
}
7

Swift 2.0:

Добавьте UIScrollView и добавьте textFields вверху. Сделайте ссылки на раскадровку на VC.

@IBOutlet weak var username: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var scrollView: UIScrollView!

Добавьте следующие методы: UITextFieldDelegate и UIScrollViewDelegate.

//MARK:- TEXTFIELD METHODS
    func textFieldShouldReturn(textField: UITextField) -> Bool {

        if(username.returnKeyType == UIReturnKeyType.Default) {
            password.becomeFirstResponder()
        }
        textField.resignFirstResponder()
        return true
    }
    func textFieldDidBeginEditing(textField: UITextField) {

        dispatch_async(dispatch_get_main_queue()) {

            let scrollPoint:CGPoint = CGPointMake(0,textField.frame.origin.y/4)
            self.scrollView!.setContentOffset(scrollPoint, animated: true);
        }
    }
    func textFieldShouldEndEditing(textField: UITextField) -> Bool {

        dispatch_async(dispatch_get_main_queue()) {
          UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true) })
        }
        return true
    }
    override func touchesBegan(touches: Set<UITouch>,
        withEvent event: UIEvent?) {
            self.view.endEditing(true)
    }
    func scrollViewWillBeginDragging(scrollView: UIScrollView) {
        self.scrollView.scrollEnabled =  true

        dispatch_async(dispatch_get_main_queue()) {
            UIView.animateWithDuration(0, animations: { self.scrollView!.setContentOffset(CGPointZero,animated: true)

            })
        }
    }
7

Попробуйте следующее:

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:self.m_Sp_Contact])
    {
        [self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];          
    }
}
7

Вам нужно добавить программно скроллинг с определенным размером кадра. Вы должны добавить UIScrollViewDelegate в файл .h. Вы должны включить scrollview для того, что вам нужно написать в viewDidLoad().

scrollview.scrollEnabled=YES;
scrollview.delegate=self;

scrollview.frame = CGRectMake(x,y,width,height);
//---set the content size of the scroll view--- 

[scrollview setContentSize:CGSizeMake(height,width)];

Таким образом вы можете добавить свои значения x, y, width и height. Я думаю, это поможет вам.

6

Я думаю, что лучший подход - использовать протокол-ориентированное программирование, если вы используете Swift.

Прежде всего, вы должны создать протокол KeyboardCapable, который дает любому UIViewController, соответствующему ему возможность регистрировать и отменить регистрацию наблюдателей на клавиатуре:

import Foundation
import UIKit

protocol KeyboardCapable: KeyboardAnimatable {
    func keyboardWillShow(notification: NSNotification)
    func keyboardWillHide(notification: NSNotification)
}

extension KeyboardCapable where Self: UIViewController {
    func registerKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil)
    }

    func unregisterKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }
}

Вы заметили постороннее ключевое слово KeyboardAnimatable на вышеуказанной части кода. Это просто имя следующего протокола, который нам нужно создать:

import Foundation
import UIKit

protocol KeyboardAnimatable {

}

extension KeyboardAnimatable where Self: UIViewController {
    func performKeyboardShowFullViewAnimation(withKeyboardHeight height: CGFloat, andDuration duration: NSTimeInterval) {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            self.view.frame = CGRectMake(view.frame.origin.x, -height, view.bounds.width, view.bounds.height)
            }, completion: nil)
    }

    func performKeyboardHideFullViewAnimation(withDuration duration: NSTimeInterval) {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            self.view.frame = CGRectMake(view.frame.origin.x, 0.0, view.bounds.width, view.bounds.height)
            }, completion: nil)
    }
}

Этот протокол KeyboardAnimatable предоставляет всем UIViewController соответствующие ему два метода, которые будут анимировать весь вид вверх и вниз соответственно.

Итак, если KeyboardCapable соответствует KeyboardAnimatable, все UIViewController, соответствующие KeyboardCapable, также соответствуют KeyboardAnimatable. Это круто.

Посмотрите на UIViewController, соответствующий KeyboardCapable, и реагируя на события клавиатуры:

import Foundation
import UIKit

class TransferConfirmViewController: UIViewController, KeyboardCapable {
    //MARK: - LIFE CYCLE       
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        registerKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        unregisterKeyboardNotifications()
    }

    //MARK: - NOTIFICATIONS
    //MARK: Keyboard
    func keyboardWillShow(notification: NSNotification) {
        let keyboardHeight = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
        let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        performKeyboardShowFullViewAnimation(withKeyboardHeight: keyboardHeight, andDuration: animationDuration)
    }

    func keyboardWillHide(notification: NSNotification) {
        let animationDuration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        performKeyboardHideFullViewAnimation(withDuration: animationDuration)
    }
}

Теперь ваш UIViewController будет реагировать на события клавиатуры и будет оживлять в последствии.

Примечание. Если вы хотите создать пользовательскую анимацию вместо того, чтобы нажимать или вытягивать представление, вы должны определить пользовательские методы в протоколе KeyboardAnimatable или выполнить их в функциях KeyboardCapable. Это зависит от вас.

6

Вот бесплатная библиотека для обработки клавиатуры Keyboard-Handling-in-iPhone-Applications. Вам нужно написать только одну строку кода:

[AutoScroller addAutoScrollTo:scrollView];

Это замечательно для обработки клавиатуры в формах

  • 0
    Зарегистрируйтесь, чтобы скачать? ..Нет, спасибо. Пожалуйста, хост на GitHub или аналогичный.
  • 0
    Интерфейс выглядит хорошо, хотя.
Показать ещё 1 комментарий
5

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

-(void)textFieldDidBeginEditing:(UITextField *)textField {
     //Show Keyboard
     self.view.frame = CGRectMake(self.view.frame.origin.x,
                              self.view.frame.origin.y-50,
                              self.view.frame.size.width,
                              self.view.frame.size.height);   
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
     // Hide keyboard
     self.view.frame = CGRectMake(self.view.frame.origin.x,
                              self.view.frame.origin.y+50,
                              self.view.frame.size.width,
                              self.view.frame.size.height); 
}
5

Гораздо более элегантным решением является использование подкласса UIView (хотя это не всегда уместно) и пересчет всех ваших подзонов при изменении родительского фрейма (и быть умным: только пересчитать их, если новый размер кадра изменилось, т.е. используйте CGRectEqualToRect для сравнения нового фрейма при переопределении setFrame и до того, как вы вызываете [super setFrame:frame_]). Единственный улов в этом заключается в том, что UIViewController, который вы собираетесь использовать, должен, вероятно, прослушивать события клавиатуры (или вы могли бы сделать это в самом UIView, для удобной инкапсуляции). Но только UIKeyboardWillShowNotification и UIKeyboardWillHideNotification. Это просто так, что он будет выглядеть гладко (если вы ждете, когда CG назовет его, вы получите момент неряшливости).

Это имеет преимущество при построении подкласса UIView, который делает все правильно. Во всяком случае.

Наивная реализация будет заключаться в переопределении drawRect: (do not), тем лучше будет просто использовать layoutSubviews (а затем в UIViewController или еще что вы можете вызвать [view setNeedsLayout] в SINGLE-методе, который вызывается для show или hide).

Это решение уходит от жесткого кодирования смещения клавиатуры (которое изменится, если оно не находится в режиме split и т.д.), а также означает, что ваше представление может быть подсмотром многих других представлений и по-прежнему правильно реагировать.

Не печатайте что-то подобное, если нет другого решения. ОС дает вам достаточно информации, если вы все сделали правильно, что вам просто нужно перерисовать разумно (на основе вашего нового размера frame). Это намного чище и способ, которым вы должны делать что-то. (Однако может быть даже лучший подход.)

Приветствия.

4

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

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 - это смещение.

4

Вот моя версия, использующая автоопределение:

Идея состоит только в том, чтобы вставлять ваше представление, содержащее текстовые поля/текстовое представление в UIScrollView, устанавливать ограничение снизу на его супервизор, делать выход и обновлять его в соответствии с высотой клавиатуры с помощью уведомлений. Это основано на примере Apple здесь, а техническая заметка Apple на UIScrollView с использованием AutoLayout здесь.

1) Вставьте свой вид V в UIScrollView S: Если вы уже установили свои константы и подпункты, вы можете скопировать/вставить ваш просмотр и подпрограммы в представлении ViewController, а затем вставить его с помощью редактора → вставить меню и, наконец, удалить скопированные представления.)

2) Задайте следующие ограничения:

  • S к руководству по началу страницы: 0
  • S в нижней макете: 0
  • S, ведущий к супервизу: 0
  • S для наблюдения: 0

  • V верхнее пространство для просмотра: 0

  • V нижнее пространство для просмотра: 0
  • V трейлинг-пространство для просмотра: 0
  • V ведущее пространство для наблюдения: 0

  • V равная ширина до S

  • Последний нижний подпункт V для просмотра: 20

3) Создайте выход из последнего ограничения на контроллер вида

4) Используйте следующий код:

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomSpaceToContentView;

// ...

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    // ...

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Handle keyboard

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

    self.bottomSpaceToContentView.constant = kBottomMargin + kbSize.height;
    [self.view layoutIfNeeded];
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    self.bottomSpaceToContentView.constant = kBottomMargin;
    [self.view layoutIfNeeded];
}

И тадааааа, это работает!

4

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

4

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

Вот базовая идея. Я внесла изменения в метод keyboardWasShown.

{
// 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 bottom edge might be at some offset from screen 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 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;
}
  • 0
    Как вы можете вернуться в исходное состояние? Я пробовал UIEdgeInsets contentInsets = UIEdgeInsetsZero; self.scrollView.contentInset = contentInsets; self.scrollView.scrollIndicatorInsets = contentInsets; как в примере, но безуспешно. Редактировать: я решил это с помощью: [self.scrollView setContentOffset: CGPointMake (0, 0)]; это нормально?
4

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

#import "UIView+avoidKeyboard.h"
#import "AppDelegate.h"

@implementation UIView (avoidKeyboard)

- (void) becomeFirstResponder {

if(self.isFirstResponder)
    return;

[super becomeFirstResponder];

if ([self isKindOfClass:[UISearchBar class]] ||
    [self isKindOfClass:[UITextField class]] ||
    [self isKindOfClass:[UITextView class]])
{
    AppDelegate *appDelegate    = [UIApplication sharedApplication].delegate;

    CGRect screenBounds         = appDelegate.window.frame;

    CGFloat keyboardHeight;
    CGFloat keyboardY;
    CGFloat viewsLowestY;
    CGPoint origin              = [self.superview convertPoint:self.frame.origin toView:appDelegate.window]; //get this views origin in terms of the main screens bounds

    if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){ //the window.frame doesnt take its orientation into account so if its sideways we must use the x value of the origin instead of the y
        keyboardHeight          = 216;
        keyboardY               = screenBounds.size.height  - keyboardHeight; //find the keyboards y coord relative to how much the main window has moved up
        viewsLowestY            = origin.y + self.frame.size.height; //find the lowest point of this view
    }
    else {
        keyboardHeight          = 162;
        keyboardY               = screenBounds.size.width  - keyboardHeight;
        viewsLowestY            = origin.x + self.frame.size.height;
    }

    CGFloat difference          = viewsLowestY - keyboardY + 20; //find if this view overlaps with the keyboard with some padding

    if (difference > 0){ //move screen up if there is an overlap

        [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{

            CGRect frame = appDelegate.window.frame;

            if(UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])){
                frame.origin.y -= difference;
            }
            else {
                frame.origin.x -= difference;
            }
            appDelegate.window.frame = frame;
        }
        completion:nil];
    }
}
}

//look at appDelegate to see when the keyboard is hidden

@end

В приложении appDelegate добавьте эту функцию

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHides:) name:UIKeyboardWillHideNotification object:nil]; //add in didFinishLaunchingWithOptions

...

- (void)keyboardHides:(NSNotification *)notification
{
    [UIView animateWithDuration:0.3 animations:^{
        [window setFrame: CGRectMake(0, 0, window.frame.size.width, window.frame.size.height)];
    } completion:nil];
}
4

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

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

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

3

Для этого вы можете использовать стороннюю библиотеку (файл pod),

pod 'RDVKeyboardAvoiding'

и ссылка https://github.com/robbdimitrov/RDVKeyboardAvoiding

3

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

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

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

3

Просто добавьте это к вашему файлу pod → pod 'IQKeyboardManager'

Вот оно, обрабатывает всю клавиатуру, прокрутки и все!

Вам не нужно ничего кодировать, не найти лучшего решения!

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

У него также есть пользовательская кнопка, которую можно удалить.

Ссылка → https://github.com/hackiftekhar/IQKeyboardManager

  • 0
    Я использовал один и тот же стручок ... и он мне очень помог .. Спасибо
3

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

Вот мой подход (слегка модифицированный способ 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

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

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

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

  • 0
    Какие лицензии есть у вашего кода?
3

Я нашел, что это лучшее решение, следуйте приведенному ниже коду:

Прикрепите ниже к вашему ограничению Vertical Space - Bottom Layout Guide - TextField.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;

Второе добавьте наблюдателей для уведомлений клавиатуры.

- (void)observeKeyboard {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

Добавьте это в свой viewDidLoad

[self observeKeyboard]; 

Наконец, методы, которые обрабатывают изменения клавиатуры.

- (void)keyboardWillShow:(NSNotification *)notification {
//THIS WILL MAKE SURE KEYBOARD DOESNT JUMP WHEN OPENING QUICKTYPE/EMOJI OR OTHER KEYBOARDS.
kbHeight = 0;
height = 0;
self.textViewBottomConst.constant = height;
self.btnViewBottomConst.constant = height;

    NSDictionary *info = [notification userInfo];
    NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    CGRect keyboardFrame = [kbFrame CGRectValue];

    CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];

    int kbHeight = finalKeyboardFrame.size.height;

    int height = kbHeight + self.textViewBottomConst.constant;

    self.textViewBottomConst.constant = height;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    self.textViewBottomConst.constant = 10;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}
3

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

https://github.com/damienromito/VisibleFormViewController

Изображение 5127

3

Недавно я оказался в аналогичном сценарии при работе над приложением для обмена сообщениями. Я создал пользовательский 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

Пожалуйста, выполните следующие действия.

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];
       }
 }
2

Попробуйте библиотеку IQKeyboard.

Это автоматически переместит текстовое поле вверх.

2

Установить прокрутку в представлении

  - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
     CGPoint point;
    if(textField == txtEmail){
      // -90 is for my you can change as per your postion
      point = CGPointMake(0, textField.frame.origin.y - 90);
    }
    else if (textField == txtContact){
      point = CGPointMake(0, textField.frame.origin.y - 90);
    }
      [scrollV setContentOffset:point animated:YES];
    }
2

Этот фрагмент кода рассчитает, сколько нужно двигаться вверх, исходя из высоты клавиатуры и глубины текстового поля. Не забудьте добавить делегат и наследовать UITextFieldDelegate в своем заголовке.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [_tbxUsername resignFirstResponder];
    [_tbxPassword resignFirstResponder];
}

- (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
{
    int animatedDistance;
    int moveUpValue = textField.frame.origin.y+ textField.frame.size.height;
    UIInterfaceOrientation orientation =
    [[UIApplication sharedApplication] statusBarOrientation];
    if (orientation == UIInterfaceOrientationPortrait ||
        orientation == UIInterfaceOrientationPortraitUpsideDown)
    {

        animatedDistance = 236-(460-moveUpValue-5);
    }
    else
    {
        animatedDistance = 182-(320-moveUpValue-5);
    }

    if(animatedDistance>0)
    {
        const int movementDistance = animatedDistance;
        const float movementDuration = 0.3f;
        int movement = (up ? -movementDistance : movementDistance);
        [UIView beginAnimations: nil context: nil];
        [UIView setAnimationBeginsFromCurrentState: YES];
        [UIView setAnimationDuration: movementDuration];
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
        [UIView commitAnimations];
    }
}

Делегировать для добавления в ViewDidLoad

_tbxUsername.delegate = self;
_tbxPassword.delegate = self;
2
  • Загрузить TPKeyBoardAvoiding По этой ссылке: https://github.com/michaeltyson/TPKeyboardAvoiding.
  • Разверните папку zipped и найдите папку TPKeyboardAvoiding.
  • Выделите все файлы .h и .m и поместите их в свой проект. Убедитесь, что элементы копии, если необходимо, отмечены галочкой.
  • Перетащите UIScrollView на StoryBoard и свяжите его с TPKeyboardAvoidingScrollView.
  • Теперь вы можете добавить элементы пользовательского интерфейса в верхней части прокрутки. Обратите внимание, что этот класс обнаруживает элементы интерфейса, даже после перетаскивания scrollView.

На вашем ViewController:

@IBOutlet weak var usernameTextfield: UITextField!
@IBOutlet weak var passwordTextfield: UITextField!
@IBOutlet weak var loginScrollView: UIScrollView!


override func viewWillAppear(animated: Bool) {
        loginScrollView.scrollEnabled =  false
    }

Добавить делегатов TextField.

//MARK:- TEXTFIELD METHODS
func textFieldShouldReturn(textField: UITextField) -> Bool
{
    if (usernameTextfield.resignFirstResponder())
    {
        passwordTextfield.becomeFirstResponder()
    }
    textField.resignFirstResponder();
    loginScrollView!.setContentOffset(CGPoint.zero, animated: true);
    loginScrollView.scrollEnabled =  false
    return true
}
func textFieldDidBeginEditing(textField: UITextField)
{
    loginScrollView.scrollEnabled =  true

    if (textField.tag  == 1 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
    {
        let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.4);
        loginScrollView!.setContentOffset(scrollPoint, animated: true);

    }
    else if (textField.tag  == 2 && (device == "iPhone" || device == "iPhone Simulator" || device == "iPod touch"))
    {
        let scrollPoint:CGPoint = CGPointMake(0, passwordTextfield.frame.origin.y/6.0);
        loginScrollView!.setContentOffset(scrollPoint, animated: true);
    }
}
func textFieldDidEndEditing(textField: UITextField)
{
    loginScrollView!.setContentOffset(CGPointZero,animated: true);
}
2

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

Вот мой подход (слегка модифицированный способ Apple) -

// Called when the UIKeyboardDidShowNotification is sent.
- (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;
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}
2

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

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillShow:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillHide:)
                                                     name:UIKeyboardWillHideNotification
                                                   object:nil];
}

- (void)keyboardWillShow:(NSNotification *)notification {
    [self adjustTextViewByKeyboardState:YES keyboardInfo:[notification userInfo]];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    [self adjustTextViewByKeyboardState:NO keyboardInfo:[notification userInfo]];
}

- (void)viewDidDisappear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super viewDidDisappear:animated];
}

- (void)adjustTextViewByKeyboardState:(BOOL)showKeyboard keyboardInfo:(NSDictionary *)info {
    CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGFloat height = keyboardFrame.size.height;
    self.constraintToAdjust.constant = height;        UIViewAnimationCurve animationCurve = [info[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
    UIViewAnimationOptions animationOptions = UIViewAnimationOptionBeginFromCurrentState;
    if (animationCurve == UIViewAnimationCurveEaseIn) {
        animationOptions |= UIViewAnimationOptionCurveEaseIn;
    }
    else if (animationCurve == UIViewAnimationCurveEaseInOut) {
        animationOptions |= UIViewAnimationOptionCurveEaseInOut;
    }
    else if (animationCurve == UIViewAnimationCurveEaseOut) {
        animationOptions |= UIViewAnimationOptionCurveEaseOut;
    }
    else if (animationCurve == UIViewAnimationCurveLinear) {
        animationOptions |= UIViewAnimationOptionCurveLinear;
    }
    [UIView animateWithDuration:[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:animationOptions animations:^{
        [self.view layoutIfNeeded];
    }                completion:nil];
}
2

Я хотел бы продлить ответ @sumanthkodi.

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

Я отредактировал код следующим образом (и портирован на Swift 2.0) и надеюсь, что он поможет некоторым людям:


1) Ссылка на вертикальное ограничение вида, которое вы хотели бы переместить вверх:

@IBOutlet var viewConstraint: NSLayoutConstraint!

Убедитесь, что вы ссылаетесь на этот var в раскадровке с ограничением.

2) Добавить делегата и реализовать слушателей. Это та же самая реализация, что и раньше:

class YourViewController: UIViewController, UITextFieldDelegate {

    ...

    func textFieldDidBeginEditing(textField: UITextField) {
        animateTextField(textField, up: true)
    }

    func textFieldDidEndEditing(textField: UITextField) {
        animateTextField(textField, up: false)
    }

    ...

}

3) Добавьте свой метод анимации animateTextField в YourViewController. Установите необходимое временное ограничение.

func animateTextField(textfield: UITextField, up: Bool) {

    let originalConstraint = 50
    let temporaryConstraint = 0
    let movementDuration = 0.3

    let constraint = CGFloat(up ? temporaryConstraint : originalConstraint)

    containerViewConstraint.constant = constraint
    UIView.animateWithDuration(movementDuration) {
        self.view.layoutIfNeeded()
    }

}
2

Это будет работать Perfectly. Прокрутка просмотра atmatically настроить по положению textfield.I уверен, что вы будете чувствовать себя хорошо

static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.25;
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;
@interface LoginVC ()
{
  CGFloat animatedDistance;
   CGRect viewFrameKey;
}

 //In ViewDidLoad
   viewFrameKey=self.view.frame;



- (void)textFieldDidBeginEditing:(UITextField *)textField
{
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 ||
    orientation == UIInterfaceOrientationPortraitUpsideDown)
{
    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
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrameKey];
[UIView commitAnimations];
}
2

Очень легкое решение может использовать KeyboardAnimator.

Проект

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

Соответствующее использование:: Он имеет конкретную реализацию для UITextField и UITextView

Ограничение:: В полной версии objective-c скоро появится скоростная версия.

2

Это можно сделать легко и автоматически, если это текстовое поле находится в ячейке таблицы (даже если table.scrollable = NO).

  • ПРИМЕЧАНИЕ: позиция и размер таблицы должны быть разумными. например:
    • если y позиция таблицы 100 подсчитана из нижней части представления, тогда клавиатура высотой 300 будет перекрывать всю таблицу.
    • если высота таблицы = 10, а текстовое поле в ней должно быть прокручено до 100, когда клавиатура появляется, чтобы быть видимой, тогда это текстовое поле будет вне таблицы.
2

Пожалуйста, добавьте эти строки в метод делегата текстового поля, чтобы прокрутить вверх в iPad.

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    activeTextfield = textField;

    CGPoint pt;
    CGRect rc = [textField bounds];
    rc = [textField convertRect:rc toView:scrlView];
    pt = rc.origin;
    pt.x = 0;
    pt.y -= 100;

    [scrlView setContentOffset:pt animated:YES];

    scrlView.contentSize = CGSizeMake(scrlView.frame.size.width, button.frame.origin.y+button.frame.size.height + 8 + 370);
}
2

Простое решение и с последней анимацией api. Изменив значение origin.y на 215, вы можете настроить его в зависимости от того, какое значение вам подходит.

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    if (self.view.frame.origin.y >= 0) {

        [UIView animateWithDuration:0.5 animations:^{
           self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-215, self.view.frame.size.width, self.view.frame.size.height);
       }];
   }
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    if (self.view.frame.origin.y < 0) {
        [UIView animateWithDuration:0.5 animations:^{
           self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+215, self.view.frame.size.width, self.view.frame.size.height);
        }];

    }
}
2
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {

  [self slideUp];
   return YES;
}

-(BOOL) textFieldShouldEndEditing:(UITextField *)textField {

    [self slideDown];
   return YES;
}

#pragma mark - Slide Up and Down animation

- (void) slideUp {
    [UIView beginAnimations:nil context:nil];
    layoutView.frame = CGRectMake(0.0, -70.0, layoutView.frame.size.width, layoutView.frame.size.height);

    [UIView commitAnimations];
}


- (void) slideDown {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDelay: 0.01]; 
    layoutView.frame = CGRectMake(0.0, 0.0, layoutView.frame.size.width, layoutView.frame.size.height);
    [UIView commitAnimations];
}
  • 0
    Вот что такое layoutView ??
2
  • Если текстовое поле не полностью или частично скрыто, мы ничего не должны изменять.
  • Мы должны вычислить точную область пересечения (рамку клавиатуры и рамки текстового поля), которая скрыта, а затем мы должны изменить рамку представления.

  • Здесь я даю полный пример.

    Объявление 3 разновидности

#define PADDING 10

@interface PKViewController ()
      @property (nonatomic, assign) CGRect originalViewFrame; //original view frame
      @property (nonatomic, strong) UITextField *activeTextField; // current text field
      @property (nonatomic, assign) CGRect keyBoardRect; // covered area by keaboard
     @end

Сохранить исходный фрейм

- (void)viewDidLoad {
    [super viewDidLoad];
    _originalViewFrame = self.view.frame;
}

Добавить контроллер просмотра в качестве наблюдателя для уведомления клавиатуры

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}

Удалить наблюдателя

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Сохраните область, закрытую клавиатурой, когда она появится, и установите ее в CGRectZero, когда она исчезнет

- (void)keyboardWasShown:(NSNotification *)notification{
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    _keyBoardRect = CGRectMake(0, _originalViewFrame.size.height - keyboardSize.height, keyboardSize.width, keyboardSize.height);
    [self moveTextFieldUP];

}
- (void) keyboardWillHide:(NSNotification *)notification{
    _keyBoardRect = CGRectZero;
    [self setDefaultFrame];
}

Сохранить активное текстовое поле

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    _activeTextField = textField;
//When keyboard is already present but the textfield is hidden. Case:When return key of  keyboard makes the next textfield as first responder
    if (!CGRectIsEmpty(_keyBoardRect)) { 
        [self moveTextFieldUP];
    }
    return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    [textField resignFirstResponder];
    return YES;
}

Теперь мы должны изменить кадр вида

- (void)moveTextFieldUP{
    CGRect virtualTextFieldRect = CGRectMake(0, self.view.frame.origin.y, _activeTextField.frame.size.width, _activeTextField.frame.origin.y+_activeTextField.frame.size.height);
    if (CGRectIntersectsRect(_keyBoardRect, virtualTextFieldRect)) {
        CGRect intersectRect = CGRectIntersection(_keyBoardRect, virtualTextFieldRect);
        CGFloat newY = _originalViewFrame.origin.y - intersectRect.size.height;
        CGFloat newHeight = _originalViewFrame.size.height + intersectRect.size.height;
        CGRect newFrame = CGRectMake(0, newY-PADDING, _originalViewFrame.size.width, newHeight+PADDING);
        [UIView animateWithDuration:0.3 animations:^{
            [self.view setFrame:newFrame];
        }];

        NSLog(@"Intersect");
    }
}
- (void)setDefaultFrame {
    [UIView animateWithDuration:0.3 animations:^{
        [self.view setFrame:_originalViewFrame];
    }];
}
2

Просто нашел этот класс:

https://github.com/OliverLetterer/SLScrollViewKeyboardSupport

И пока это хорошо работает на iPhone, включая анимацию и правильное смещение.

Чтобы использовать его, просто добавьте в viewDidLoad:

self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];
2

Здесь много ответов, но это работает и намного короче большинства:

- (void)textFieldDidBeginEditing:(UITextField *)sender
{
    UIScrollView *scrollView = (UIScrollView *)self.view; // assuming this method is pasted into the UIScrollView controller
    const double dontHardcodeTheKeyboardHeight = 162;
    double textY = [sender convertPoint:CGPointMake(0, 0) toView:scrollView].y;
    if (textY - scrollView.contentOffset.y + sender.frame.size.height > self.view.frame.size.height - dontHardcodeTheKeyboardHeight)
        [scrollView setContentOffset:CGPointMake(0.0, textY - 10) animated:YES];
}
1

Простое решение для Scrollview с TextFields ниже, не нужно никаких ограничений или активного текстового поля и т.д.

 override func viewWillAppear(_ animated: Bool){
        super.viewWillAppear(animated)
        registerForKeyboardNotifications();


    }
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        deregisterFromKeyboardNotifications();
    }
    //MARK:- KEYBOARD DELEGATE METHODS
        func registerForKeyboardNotifications(){
            //Adding notifies on keyboard appearing
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        }
        func deregisterFromKeyboardNotifications(){
            //Removing notifies on keyboard appearing
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        }
        func keyboardWasShown(notification: NSNotification){

            var info = notification.userInfo!
            let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
            var contentInset:UIEdgeInsets = self.scrRegister.contentInset
            contentInset.bottom = (keyboardSize?.height)!
            scrRegister.contentInset = contentInset


        }
        func keyboardWillBeHidden(notification: NSNotification)
        {
            var contentInset:UIEdgeInsets = self.scrRegister.contentInset
            contentInset.bottom = 0
            scrRegister.contentInset = contentInset

        }
1

Swift 3.0 версия кода управления клавиатурой Apple: FloatingTF, используемый в приведенном ниже коде, является текстовым полем, основанным на материалах, в iOS.

import UIKit
class SignupViewController: UIViewController, UITextFieldDelegate {

    //MARK: - IBOutlet:
@IBOutlet weak var emailTF: FloatingTF!
@IBOutlet weak var passwordTF: FloatingTF!
@IBOutlet weak var dobTF: FloatingTF!

@IBOutlet weak var scrollView: UIScrollView!

//MARK: - Variable:
var activeTextField: UITextField!

//MARK: - ViewController Lifecycle:
override func viewDidLoad() {
    super.viewDidLoad()        
    emailTF.delegate = self
    passwordTF.delegate = self
    dobTF.delegate = self 
}
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    registerKeyboardNotifications()
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

   deRegisterKeyboardNotifications()
}

//MARK: - Keyboard notification observer Methods
fileprivate func registerKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(SignupViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
fileprivate func deRegisterKeyboardNotifications() {
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: self.view.window)
}
func keyboardWillShow(notification: NSNotification) {

    let info: NSDictionary = notification.userInfo! as NSDictionary
    let value: NSValue = info.value(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValue
    let keyboardSize: CGSize = value.cgRectValue.size
    let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    // If active text field is hidden by keyboard, scroll it so it visible
    // Your app might not need or want this behavior.
    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize.height
    let activeTextFieldRect: CGRect? = activeTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin
    if (!aRect.contains(activeTextFieldOrigin!)) {
        scrollView.scrollRectToVisible(activeTextFieldRect!, animated:true)
    }    }

func keyboardWillHide(notification: NSNotification) {
    let contentInsets: UIEdgeInsets = .zero
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

//MARK: - UITextField Delegate Methods
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if textField == emailTF {
        passwordTF.becomeFirstResponder()
    }
    else if textField == passwordTF {
        dobTF.becomeFirstResponder()
    }
    else {
        self.view.endEditing(true)
    }
    return true
}

func textFieldDidBeginEditing(_ textField: UITextField) {
    activeTextField = textField
    scrollView.isScrollEnabled = true
}

func textFieldDidEndEditing(_ textField: UITextField) {
    activeTextField = nil
    scrollView.isScrollEnabled = false
}
}
1

просто: -

В TextFieldDidBeginEditing: -

self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y-150, self.view.frame.size.width, self.view.frame.size.height);

В TextFieldShouldEndEditing: -

self.view.frame=CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+150, self.view.frame.size.width, self.view.frame.size.height);
  • 0
    это отлично работало с XIB-файлом, отображаемым в виде всплывающего окна
1

Пожалуйста, выполните следующие действия, это может быть полезно. Поместите один вид, затем поместите свое текстовое поле в это представление и определите событие делегатом, когда ваша клавиатура поднимется, в то время мгновенно оживите представление (вы также можете назначить некоторую позицию для этого вида), тогда ваше представление будет расти к этой позиции. То же самое для анимации представления вниз.

Спасибо

0

Пожалуйста, используйте IQKeyboardManager, используйте следующую ссылку: https://github.com/hackiftekhar/IQKeyboardManager

0

Если текстовое поле должно быть внизу экрана, то самым волшебным решением является переопределение на вашем контроллере вида:

override var inputAccessoryView: UIView? {
    return <yourTextField>
}
0

Добавьте мои 5 центов :)

Я всегда предпочитаю использовать tableView для inputTextField или scrollView. В сочетании с уведомлениями вы можете легко управлять таким поведением. (Обратите внимание, если вы используете статические ячейки в tableView, такое поведение будет работать автоматически).

// MARK: - Notifications
fileprivate func registerNotificaitions() {
    NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillAppear(_:)),
                                           name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(AddRemoteControlViewController.keyboardWillDisappear),
                                           name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

fileprivate func unregisterNotifications() {
    NotificationCenter.default.removeObserver(self)
}

@objc fileprivate func keyboardWillAppear(_ notification: Notification) {
    if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
        view.layoutIfNeeded()
        UIView.animate(withDuration: 0.3, animations: {
            let heightInset = keyboardHeight - self.addDeviceButton.frame.height
            self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: heightInset, right: 0)
            self.view.layoutIfNeeded()
        }, completion: nil)
    }
}

@objc fileprivate func keyboardWillDisappear() {
    view.layoutIfNeeded()
    UIView.animate(withDuration: 0.3, animations: {
        self.tableView.contentInset = UIEdgeInsets.zero
        self.view.layoutIfNeeded()
    }, completion: nil)
}
0

Мы можем пользовательский код для Swift 4.1

    let keyBoardSize = 80.0

    func keyboardWillShow() {

    if view.frame.origin.y >= 0 {
    viewMovedUp = true
     }
     else if view.frame.origin.y < 0 {
    viewMovedUp = false
   }
  }

func keyboardWillHide() {
 if view.frame.origin.y >= 0 {
    viewMovedUp = true
 }
 else if view.frame.origin.y < 0 {
    viewMovedUp = false
 }

}

func textFieldDidBeginEditing(_ textField: UITextField) {
   if sender.isEqual(mailTf) {
    //move the main view, so that the keyboard does not hide it.
    if view.frame.origin.y >= 0 {
        viewMovedUp = true
    }
  }
}

func setViewMovedUp(_ movedUp: Bool) {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.3)
    // if you want to slide up the view
let rect: CGRect = view.frame
if movedUp {

    rect.origin.y -= keyBoardSize
    rect.size.height += keyBoardSize
}
else {
    // revert back to the normal state.
    rect.origin.y += keyBoardSize
    rect.size.height -= keyBoardSize
 }
 view.frame = rect
 UIView.commitAnimations()
}

func viewWillAppear(_ animated: Bool)  {
super.viewWillAppear(animated)

NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector:#selector(self.keyboardWillHide), name: .UIKeyboardWillHide, object: nil)
}

func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)

NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
0

См. Следующие

import UIKit
@available(tvOS, unavailable)
public class KeyboardLayoutConstraint: NSLayoutConstraint {

    private var offset : CGFloat = 0
    private var keyboardVisibleHeight : CGFloat = 0

    @available(tvOS, unavailable)
    override public func awakeFromNib() {
        super.awakeFromNib()

        offset = constant

        NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    // MARK: Notification

    @objc func keyboardWillShowNotification(_ notification: Notification) {
        if let userInfo = notification.userInfo {
            if let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue {
                let frame = frameValue.cgRectValue
                keyboardVisibleHeight = frame.size.height
            }

            self.updateConstant()
            switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
            case let (.some(duration), .some(curve)):

                let options = UIViewAnimationOptions(rawValue: curve.uintValue)

                UIView.animate(
                    withDuration: TimeInterval(duration.doubleValue),
                    delay: 0,
                    options: options,
                    animations: {
                        UIApplication.shared.keyWindow?.layoutIfNeeded()
                        return
                    }, completion: { finished in
                })
            default:

                break
            }

        }

    }

    @objc func keyboardWillHideNotification(_ notification: NSNotification) {
        keyboardVisibleHeight = 0
        self.updateConstant()

        if let userInfo = notification.userInfo {

            switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) {
            case let (.some(duration), .some(curve)):

                let options = UIViewAnimationOptions(rawValue: curve.uintValue)

                UIView.animate(
                    withDuration: TimeInterval(duration.doubleValue),
                    delay: 0,
                    options: options,
                    animations: {
                        UIApplication.shared.keyWindow?.layoutIfNeeded()
                        return
                    }, completion: { finished in
                })
            default:
                break
            }
        }
    }

    func updateConstant() {
        self.constant = offset + keyboardVisibleHeight
    }

}
0

На этот вопрос уже есть много ответов, некоторые сказали, что используют представление прокрутки, некоторые сказали, что используют третью библиотеку.

Но для меня идеей решения должен быть UITableViewController со статическими ячейками.

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

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

0

Вы можете использовать этот простой репозиторий Git: https://github.com/hackiftekhar/IQKeyboardManager

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

Согласно их readme, интеграция очень проста:

, без необходимости вводить код, и никакой дополнительной настройки не требуется. Чтобы использовать IQKeyboardManager, вам просто нужно добавить исходные файлы в свой проект

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

0

Я немного опаздываю. Вы должны добавить scrollView на свой viewController.

Вы должны реализовать метод ниже 2.

Метод делегата TextField.

    - (void)textFieldDidBeginEditing:(UIView *)textField {
    [self scrollViewForTextField:reEnterPINTextField];
}

Затем вызовите метод meton в методе делегата.

 - (void)scrollViewForTextField:(UIView *)textField {
    NSInteger keyboardHeight = KEYBOARD_HEIGHT;

    if ([textField UITextField.class]) {
        keyboardHeight += ((UITextField *)textField).keyboardControl.activeField.inputAccessoryView.frame.size.height;
    } 

    CGRect screenFrame = [UIScreen mainScreen].bounds;
    CGRect aRect = (CGRect){0, 0, screenFrame.size.width, screenFrame.size.height - ([UIApplication sharedApplication].statusBarHidden ? 0 : [UIApplication sharedApplication].statusBarFrame.size.height)};
    aRect.size.height -= keyboardHeight;
    CGPoint relativeOrigin = [UIView getOriginRelativeToScreenBounds:textField];
    CGPoint bottomPointOfTextField = CGPointMake(relativeOrigin.x, relativeOrigin.y + textField.frame.size.height);

    if (!CGRectContainsPoint(aRect, bottomPointOfTextField) ) {
        CGPoint scrollPoint = CGPointMake(0.0, bottomPointOfTextField.y -aRect.size.height);
        [contentSlidingView setContentOffset:scrollPoint animated:YES];
    }
}
0

У меня возникла проблема с переходом к основному виду по умолчанию при изменении текстового поля или редактировании его содержимого (например, текстовое поле телефона и добавление знака "-", а просмотр - закрытие текстовых полей) i finnaly преодолевает это, используя автоматическую компоновку и изменяя ограничения постоянными, а не размер кадра или позицию в функции делегирования уведомлений, например:

P.S. Я не использую scrollview только для простого перемещения, но он должен работать с аналогичным

func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
    if !keyboardIsShown{
        self.infoViewTopConstraint.constant -= keyboardSize.height
        self.infoViewBottomConstraint.constant += keyboardSize.height
        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()
        keyboardIsShown = true
    }
}

func keyboardWillHide(notification: NSNotification) {
if keyboardIsShown {
    self.infoViewTopConstraint.constant += keyboardSize.height
    self.infoViewBottomConstraint.constant -= keyboardSize.height
    self.view.setNeedsLayout()
    self.view.layoutIfNeeded()
    keyboardIsShown = false
}
0

В iOS перемещение клавиатуры вверх и возврат для текстовых полей в приложении немного запутанно и нужно реализовать несколько методов для них. вам также необходимо сделать делегат текстовым полем и позаботиться об этом. Код для него будет повторяться в каждом классе, где существуют текстовые поля.

Я предпочитаю использовать этот контроль Github.

IQKeyboard

В котором Нам не нужно ничего делать. - просто перетащите элемент управления перетаскиванием в свой проект и создайте. - Он сделает все для вашего приложения.

Спасибо

Возможно, это будет полезно.

  • 1
    это именно то, что я ищу. Благодарю . Я сразу же это сделаю.
0

Это сработало для меня:

func setupKeyboardNotifications() {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWasShown:"), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillBeHidden:"), name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWasShown(aNotification:NSNotification) {
    let info = aNotification.userInfo
    let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
    let kbSize = infoNSValue.CGRectValue().size
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3)
    var rect : CGRect = self.view.frame
    rect.size.height -= kbSize.height

    self.view.frame = rect
    UIView.commitAnimations()
}

func keyboardWillBeHidden(aNotification:NSNotification) {
    let info = aNotification.userInfo
    let infoNSValue = info![UIKeyboardFrameBeginUserInfoKey] as NSValue
    let kbSize = infoNSValue.CGRectValue().size
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationDuration(0.3)
    var rect : CGRect = self.view.frame
    rect.size.height += kbSize.height
    self.view.frame = rect
    UIView.commitAnimations()
}
0

Я использую Swift и auto layout (но не могу прокомментировать предыдущий ответ Swift); здесь, как я делаю это без прокрутки:

Я компоную свою форму в IB с вертикальными ограничениями между полями, чтобы их разделить. Я добавляю вертикальное ограничение от самого верхнего поля к представлению контейнера и создаю для него выход (topSpaceForFormConstraint в коде ниже). Все, что нужно, это обновить это ограничение, которое я делаю в блоке анимации для приятного мягкого движения. Конечно, проверка высоты необязательна, в этом случае мне нужно было сделать это только для наименьшего размера экрана.

Это можно вызвать с помощью любого из обычных методов textFieldDidBeginEditing или keyboardWillShow.

func setFormHeight(top: CGFloat)
{
    let height = UIScreen.mainScreen().bounds.size.height

    // restore text input fields for iPhone 4/4s
    if (height < 568) {
        UIView.animateWithDuration(0.2, delay: 0.0, options: nil, animations: {
            self.topSpaceForFormConstraint.constant = top
            self.view.layoutIfNeeded()
            }, completion: nil)
    }

}
0

in (BOOL) textFieldShouldBeginEditing: (UITextField *) textField

if (textField.frame.origin.y > self.view.frame.size.height - 216)
    {
        if (screenHeight>500)
            scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 100);
        else
            scrollView.contentSize = CGSizeMake(0.0, scrollView.contentSize.height + 216);
        CGPoint scrollPoint = CGPointMake(0.0,(textField.frame.origin.y - (self.view.frame.size.height - 216 - textField.frame.size.height - 20)));
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
    [scrollView setScrollEnabled:YES];

при отставке keyBoard вам нужно написать следующий код

scrollView.contentSize = CGSizeMake(0.0, 640);
CGPoint scrollPoint = CGPointMake(0.0,0.0);
[scrollView setContentOffset:scrollPoint animated:YES]; 
0

Я нашел @DK_ для решения, которое начал использовать. Однако есть предположение, что scrollView охватывает весь вид. Это было не так для меня. Я только хотел scrollView в случае, если клавиатура закрыла нижнее текстовое поле на моем экране входа в систему. Поэтому мой контент был такого же размера, как и мой вид прокрутки, который был меньше основного.

Он также не учитывал пейзажи, с которых я начал беспокоиться. После нескольких дней работы с ним это мой метод keyboardWasShown:.

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    // A lot of the inspiration for this code came from http://stackoverflow.com/a/4837510/594602
    CGFloat height = 0;
    NSDictionary* info = [aNotification userInfo];

    CGRect kbFrameRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect kbBoundsRect = [self.view convertRect:kbFrameRect fromView:nil]; // Convert frame from window to view coordinates.

    CGRect scrollRect = scrollView.frame;
    CGRect intersect = CGRectIntersection(kbBoundsRect, scrollRect);

    if (!CGRectIsNull(intersect))
    {
        height = intersect.size.height;
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // Figure out what the view rectangle is for the scrollView
    CGPoint contentOffset = scrollView.contentOffset;
    CGRect visibleRect = CGRectOffset(scrollRect, contentOffset.x, contentOffset.y);    // I'm not 100% sure if this is needed/right. My scrollView was always at the top in testing.
    visibleRect.size.height -= height;
    CGRect activeRect = activeField.frame;

    if (!CGRectContainsRect(visibleRect, activeRect))
    {
        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
    }
}

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

Я думаю, что ключевая часть заключалась в том, что представление контента имело заданную ширину и высоту. Это позволило просматривать прокрутку, чтобы точно знать, сколько контента ей пришлось иметь. Это немного отстает от обычных макетов. Обычно взгляды пытаются взять как можно больше места. С содержимым вида прокрутки вы пытаетесь получить представление как можно больше. Представление контента позволяет вам остановиться на этом. Поэтому я дал мне высоту 248 и использовал стандартную ширину экрана 320 в качестве моей ширины.

Макеты, которые в конечном итоге сработали для меня, были следующими:

  • Scroll View to super view: В основном я дал ограничения для верхнего, левого и правого.
    • Horizontal Space - View - Scroll View (0)
    • Vertical Space - View - Scroll View (0)
    • Horizontal Space - Scroll View - View (0)
  • Прокрутка Высота просмотра: я устанавливаю вид прокрутки с постоянной высотой. Я не знаю, действительно ли это было необходимо, но оно получило границы прокрутки.
    • Height - (248) - Scroll View
  • Вид содержимого в виде прокрутки: я дал константы со всех сторон, сверху, слева, внизу и справа.
    • Vertical Space - View - Scroll View (0)
    • Vertical Space - Scroll View - View (0)
    • Horizontal Space - View - Scroll View (0)
    • Horizontal Space - Scroll View - View (0)
  • Размеры представления содержимого.
    • Height - (248) - View
    • Width - (320) - View
0

Я не видел эту возможность здесь, поэтому я добавляю ее, так как я пробовал методы в ответах, но через несколько часов обнаружил, что в XCode 5 в iOS6/7 есть намного более простой способ: Используйте NSLayoutConstraints.

Смотрите: Ограничение автоопределения - Клавиатура

Вот мой код:

.m file:

// Called when the UIKeyboardWillShowNotification is sent.
- (void)keyboardWillBeShown:(NSNotification*)aNotification
{
    NSLog(@"keyboardWillBeShown:");
    [self.PhoneNumberLabelOutlet setHidden:TRUE];
    CGFloat heightOfLabel = self.PhoneNumberLabelOutlet.frame.size.height;
    for( NSLayoutConstraint* thisConstraint in self.topElementsVerticalDistanceFromTopLayoutConstraint ) {
        thisConstraint.constant -= heightOfLabel;
    }

    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGFloat oldConstant = [self.SignInYConstraint constant];
    self.SignInYConstraint.constant = oldConstant + kbSize.height;
    [self.view setNeedsUpdateConstraints];

    NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration:duration animations:^{
        [self.view layoutIfNeeded];
    }];

}

.h файл:

#import <UIKit/UIKit.h>

@interface SignInViewController : UIViewController {

    UITextField* _activeField;
}




- (void)signInCallback:(NSObject*)object;


@property (weak, nonatomic) IBOutlet UILabel *PhoneNumberLabelOutlet;

@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *ActivityIndicatorOutlet;

@property (weak, nonatomic) IBOutlet UITextField *UserIDTextfieldOutlet;

@property (weak, nonatomic) IBOutlet UITextField *PasswordTextfieldOutlet;

@property (weak, nonatomic) IBOutlet UIButton *SignInButton;

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *SignInYConstraint;

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *topElementsVerticalDistanceFromTopLayoutConstraint;

@end
0

ЕСЛИ ВЫ ВСЕГДА БЫВАЕТЕ С ЭТОЙ - ПРОЧИТАЙТЕ МОЮ ПОЧТУ

Сегодня я нашел решение. Я читал многочисленные сообщения и "учебные пособия" об этой проблеме, и НИ ОДИН из них не работает в каждом случае (большинство из них являются копиями друг друга). Даже Apple официально предложила "решение" не работает, и больше, она полностью не работает в ландшафтном режиме. Позор для Apple за то, что он не дает разработчикам средств для решения такой общей основной проблемы. Очень непрофессионально. Такая удивительная структура (Cocoa) и такая неприятная недооцененная проблема.

Теперь мое решение: сделайте UIScrollView своим корневым представлением, а затем поместите все в него. Затем подкласс контроллера вашего вида из этого класса KeyboardAwareController (вы можете переопределить методы прокрутки и клавиатуры):

//   //KeyboardAwareController.h   // Социопатия   //   // Создано администратором 13.01.14.   // Авторское право (c) 2014 кучумов. Все права защищены.   //

#import <UIKit/UIKit.h>

@interface KeyboardAwareController : UIViewController <UITextFieldDelegate>

@end

//   //KeyboardAwareController.m   // Социопатия   //   // Создано администратором 13.01.14.   // Авторское право (c) 2014 кучумов. Все права защищены.   //

#import "KeyboardAwareController.h"

@interface KeyboardAwareController ()

@end

@implementation KeyboardAwareController
{
    CGPoint scrollPositionBeforeKeyboardAdjustments;

    __weak UIScrollView* scrollView;

    UITextField* activeField;
}

- (id) initWithCoder: (NSCoder*) decoder
{
    if (self = [super initWithCoder:decoder])
    {
        scrollPositionBeforeKeyboardAdjustments = CGPointZero;
    }
    return self;
}

- (void) viewDidLoad
{
    [super viewDidLoad];
}

- (UIScrollView*) scrollView
{
    return (UIScrollView*) self.view;
}

- (CGFloat) keyboardPadding
{
    return 5;
}

- (void) registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardDidShow:)
                                                 name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void) deregisterFromKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardDidShowNotification
                                                  object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

- (void) viewWillAppear: (BOOL) animated
{
    [super viewWillAppear:animated];

    [self registerForKeyboardNotifications];
}

- (void) viewWillDisappear: (BOOL) animated
{
    [self deregisterFromKeyboardNotifications];

    [super viewWillDisappear:animated];
}

- (void) keyboardWillShow: (NSNotification*) notification
{
    //NSLog(@"keyboardWillShow");

    // force the animation from keyboardWillBeHidden: to end
    scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;

    scrollPositionBeforeKeyboardAdjustments = CGPointZero;
}

// warning: i have no idea why this thing works and what does every line of this code mean
// (but it works and there is no other solution on the internets whatsoever)
// P.S. Shame on Apple for missing such a basic functionality from SDK (and many other basic features we have to hack and mess around with for days and nights)

- (void) keyboardDidShow: (NSNotification*) notification
{
    //NSLog(@"keyboardDidShow");

    UIWindow* window = [[[UIApplication sharedApplication] windows]objectAtIndex:0];
    UIView* mainSubviewOfWindow = window.rootViewController.view;

    CGRect keyboardFrameIncorrect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect keyboardFrame = [mainSubviewOfWindow convertRect:keyboardFrameIncorrect fromView:window];
    CGSize keyboardSize = keyboardFrame.size;

    CGRect visibleFrame = CGRectMake(0, 0, 0, 0);
    visibleFrame.origin = self.scrollView.contentOffset;
    visibleFrame.size = self.scrollView.bounds.size;

    CGFloat paddedKeyboardHeight = keyboardSize.height + self.keyboardPadding;

    //NSLog(@"visibleFrame %@", NSStringFromCGRect(visibleFrame));

    visibleFrame.size.height -= paddedKeyboardHeight;

    //NSLog(@"visibleFrame after keyboard height %@", NSStringFromCGRect(visibleFrame));

    if (CGRectContainsPoint(visibleFrame, activeField.frame.origin))
        return;

    scrollPositionBeforeKeyboardAdjustments = scrollView.contentOffset;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height, 0);

    contentInsets = UIEdgeInsetsMake(0.0, 0.0, paddedKeyboardHeight, 0);

    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;

    CGSize scrollContentSize = self.scrollView.bounds.size;
    scrollContentSize.height += paddedKeyboardHeight;
    self.scrollView.contentSize = scrollContentSize;

    //NSLog(@"scrollView %@", NSStringFromCGRect(scrollView.frame));
    //NSLog(@"activeField %@", NSStringFromCGRect(activeField.frame));

    //[scrollView scrollRectToVisible:activeField.frame animated:YES];

    CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y - visibleFrame.size.height + activeField.frame.size.height);

    //NSLog(@"scrollPoint %@", NSStringFromCGPoint(scrollPoint));

    [self.scrollView setContentOffset:scrollPoint animated:YES];
}

- (void) keyboardWillBeHidden: (NSNotification*) notification
{
    //NSLog(@"keyboardWillBeHidden");

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    // this doesn't work when changing orientation while the keyboard is visible
    // because when keyboardDidShow: will be called right after this method the contentOffset will still be equal to the old value
    //[scrollView setContentOffset:scrollPositionBeforeKeyboardAdjustments animated:YES];

    [UIView animateWithDuration:.25 animations:^
    {
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;

        // replacement for setContentOffset:animated:
        self.scrollView.contentOffset = scrollPositionBeforeKeyboardAdjustments;
    }];
}

- (void) textFieldDidBeginEditing: (UITextField*) textField
{
    activeField = textField;
}

- (void) textFieldDidEndEditing: (UITextField*) textField
{
    activeField = nil;
}
@end

Если у вас есть какие-либо вопросы, мой проект размещен здесь на github: https://github.com/kuchumovn/sociopathy.ios

Я также сделал снимок экрана для лучшего объяснения: Изображение 5129

  • 2
    Было бы полезно получить отзывы от людей, которые проголосовали против этого ответа.
0

см. UICatalogView примеры iphone live и загруженные

-2

Для Swift Developer, использующего Swift 3, здесь находится repo https://github.com/jamesrochabrun/KeyboardWillShow

import UIKit

class ViewController: UIViewController {

    //1 Create a view that will hold your TEXTFIELD
    let textField: UITextField = {
        let tf = UITextField()
        tf.translatesAutoresizingMaskIntoConstraints = false
        tf.layer.borderColor = UIColor.darkGray.cgColor
        tf.layer.borderWidth = 3.0
        return tf
    }()
    //2 global variable that will hold the bottom constraint on changes
    var textfieldBottomAnchor: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
        //3 add the view to your controller
        view.addSubview(textField)
        textField.heightAnchor.constraint(equalToConstant: 80).isActive = true
        textField.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true
        textField.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        textfieldBottomAnchor = textField.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        textfieldBottomAnchor?.isActive = true

        setUpKeyBoardObservers()
    }
    //4 Use NSnotificationCenter to monitor the keyboard updates
    func setUpKeyBoardObservers() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

    //5 toggle the bottom layout global variable based on the keyboard height
    func handleKeyboardWillShow(notification: NSNotification) {

        let keyboardFrame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? CGRect
        if let keyboardFrame = keyboardFrame {
            textfieldBottomAnchor?.constant = -keyboardFrame.height
        }
        let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
        if let keyboardDuration = keyboardDuration {
            UIView.animate(withDuration: keyboardDuration, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }

    func handleKeyboardWillHide(notification: NSNotification) {

        textfieldBottomAnchor?.constant = 0
        let keyboardDuration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double
        if let keyboardDuration = keyboardDuration {
            UIView.animate(withDuration: keyboardDuration, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }
    //6 remove the observers
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        NotificationCenter.default.removeObserver(self)
    }
}
-2

Вам не нужно полагаться на создание пользовательского кода для перемещения любого вида вверх, когда клавиатура появится Вы можете просто пользовательскую библиотеку IQKeyboardManagerSwift тот же доступный для кода Objective-C также

-5

Попробуйте сделать это отлично:

if Firstnametxt.text == "" || Passwordtxt.text == "" || emailtxt.text == ""
    {
        if Firstnametxt.text == ""
        {
            Firstnametxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            Firstnametxt.becomeFirstResponder()
        }
        else if Passwordtxt.text == ""
        {
            Passwordtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            Passwordtxt.becomeFirstResponder()
        }
        else if emailtxt.text == ""

        {

            emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            emailtxt.becomeFirstResponder()
        }

    }
    else
    {
        let isValidEmail:Bool = self.isValidEmail(emailtxt.text!)
        if isValidEmail == true
        {
                        }
        else
        {
            emailtxt!.shake(10, withDelta: 5, speed: 0.05, shakeDirection: ShakeDirection.Horizontal)
            emailtxt.becomeFirstResponder()

        }

    }
  • 0
    Лучше включить некоторый контекст / объяснение в код, поскольку это делает ответ более полезным для ОП и для будущих читателей.
-7

Прежде всего, я рекомендую лучший дизайн для вашей страницы, чтобы не было необходимости прокручивать ваш вид. Если у вас много текстовых полей, вам все равно не нужно использовать ScrollView, он просто усложняет задачу. Вы можете просто добавить контейнер UIView в верхней части исходного представления контроллера, а затем поместить эти текстовые поля в это представление. Когда клавиатура отображается или исчезает, просто используйте анимацию, чтобы переместить это представление контейнера.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню