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

avatar
philfreo
14 июля 2009 в 17:06
639052
98
1745

С iOS SDK:

У меня есть UIView с 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
}

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

Источник
Pankaj Kainthla
2 февраля 2011 в 08:03
0

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

Aruna
19 августа 2011 в 19:18
7

Проверь это. Никаких хлопот для вас. TPKeyboardAvoading

user1199624
31 июля 2013 в 05:24
22

Это задокументировано Apple, я думаю, что это лучший способ: developer.apple.com/library/ios/#documentation/StringsTextFonts/…

neoneye
29 августа 2013 в 23:45
0

Автоматическая раскладка и раскладка с учетом клавиатуры, автор ghawk.gu В статье также рассказывается, как работать с книжной и альбомной ориентацией.

Durai Amuthan.H
24 сентября 2013 в 07:58
0

В приведенной ниже ссылке объясняется, как прокручивать представление для отображения полей, включая UITextField , очень четко скрытого с клавиатуры с четким кодом и диаграммами Щелкните меня 1 Ссылка на концентратор git ниже дает работающий исходный код Нажми меня 2

Binarian
28 сентября 2013 в 09:12
0

Очень хорошее руководство с изображениями находится по адресу: cocoawithlove.com/2008/10/…

NSS
14 декабря 2013 в 09:05
0

Это хорошее решение сработало для меня: github.com/simonbs/BSKeyboardControls

Pradeep Mittal
10 февраля 2014 в 10:10
59

Используйте этот код. Вам просто нужна 1 строка в файле appdelegate.m, и он работает. github.com/hackiftekhar/IQKeyboardManager

Mongi Zaidi
26 марта 2014 в 10:30
9

Лучший способ, который я нашел до сих пор, - это открытый исходный код TPKeyboardAvoiding

Sofeda
24 марта 2016 в 11:42
0

IQKeyboardManager не работает в портретном режиме 4s

Julian Corrêa
26 апреля 2016 в 11:59
0

Эти решения были для меня лучше: coderhelper.com/a/15036744/1234031

Naresh Reddy M
5 августа 2016 в 16:09
0

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

Burak
8 августа 2016 в 15:01
0

Для тех, кто использует storyboard и пытается заставить его работать, но не может, просто убедитесь, что self.view имеет ведущий , верхний и конечный 389 constraints> определено. В противном случае это, вероятно, не сработает для IQKeyboardManager или для ответов ниже.

Dhruv Narayan Singh
6 декабря 2016 в 13:09
0

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

abhimuralidharan
27 февраля 2017 в 08:17
0

Код управления клавиатурой Apple Swift 3.0 находится здесь: medium.com/@abhimuralidharan/…

Fattie
30 ноября 2017 в 20:18
0

Возможный дубликат Измените размер экрана при появлении клавиатуры

Vicky Dhas
9 декабря 2017 в 11:04
2

Другой способ - добавить такие текстовые поля содержимого и все в TableViewController и позволить tableview обрабатывать это.

Venkatesh G
22 февраля 2018 в 09:28
0

Перейдите по ссылке ниже: coderhelper.com/questions/48922266/…

Fattie
17 октября 2019 в 11:26
0

вот общее, простое и популярное решение ! coderhelper.com/a/41808338/294884

keshav
23 июля 2021 в 06:14
0

coderhelper.com/questions/1126726/…

Ответы (98)

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

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

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

#define kOFFSET_FOR_KEYBOARD 80.0

-(void)keyboardWillShow {
    // Animate the current view out of the way
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)keyboardWillHide {
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:mailTf])
    {
        //move the main view, so that the keyboard does not hide it.
        if  (self.view.frame.origin.y >= 0)
        {
            [self setViewMovedUp:YES];
        }
    }
}

//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3]; // if you want to slide up the view

    CGRect rect = self.view.frame;
    if (movedUp)
    {
        // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
        // 2. increase the size of the view so that the area behind the keyboard is covered up.
        rect.origin.y -= kOFFSET_FOR_KEYBOARD;
        rect.size.height += kOFFSET_FOR_KEYBOARD;
    }
    else
    {
        // revert back to the normal state.
        rect.origin.y += kOFFSET_FOR_KEYBOARD;
        rect.size.height -= kOFFSET_FOR_KEYBOARD;
    }
    self.view.frame = rect;

    [UIView commitAnimations];
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

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

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}
Cocoa Dev
14 декабря 2010 в 17:56
3

Что значит _textField? Я скопировал его в свой код, он говорит, что _textField не объявлен.

patrick
28 января 2011 в 13:02
0

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

Abduliam Rehmanius
26 июня 2011 в 04:08
0

Разве это не тесто для вызова - (void) setViewMovedUp: (BOOL) moveUp в событиях keyBoardWillSHow и KeyBoardWillHide !!

Michael
29 июля 2011 в 18:02
0

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

Amit Battan
9 мая 2012 в 17:49
0

возникает проблема с UIInterfaceOrientation LandscapeRight и UIInterfaceOrientation LandscapeRight. . . . Мое приложение работает только в альбомной ориентации

FractalDoctor
2 декабря 2012 в 16:00
4

Не особенно полезно, если вы поддерживаете вращение основного вида.

AlexChaffee
12 февраля 2013 в 23:52
0

Мне нравится ваше решение, но я думаю, что могу сделать его еще проще: не беспокойтесь о материалах Notification Observer; вместо этого вызывайте правильные процедуры анимации внутри соответствующих методов делегата - для UITextView это textViewDidBeginEditing и textViewDidEndEditing.

zzzzz
19 марта 2013 в 07:40
0

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

Jeff
20 июля 2013 в 08:41
0

Определенно не меняйте Y - нужно изменить высоту!

IKKA
7 сентября 2013 в 10:20
0

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

ZviBar
25 марта 2014 в 12:00
0

Вам вообще не нужно вставлять анимированный метод - (void) viewWillAppear: (BOOL). Это просто все портит.

Puttin
14 апреля 2015 в 08:03
0

Используйте NPKeyboardLayoutGuide, если вы используете AutoLayout.

Ky Leggiero
2 ноября 2015 в 19:48
0

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

W.K.S
26 июня 2016 в 11:10
0

@ user1519240: Этот пост работал у меня после того, как я прокомментировал !CGRectContainsPoint(aRect, activeField!.frame.origin). Спасибо :)

Burak
8 августа 2016 в 14:54
0

Для тех, кто использует storyboard и пытается заставить его работать, но не может, просто убедитесь, что self.view имеет ведущий , верхний и замыкающий <87164541264> constraints>. В противном случае, вероятно, не получится.

avance
21 сентября 2016 в 22:23
2

Чтобы это сработало, мне пришлось закомментировать раздел textFieldDidBeginEditing.

Purushothaman
11 ноября 2016 в 07:05
0

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

Andy Weinstein
29 июня 2017 в 13:46
0

У меня не получилось. Если это не сработает для вас, я рекомендую добавить в раскадровку прокрутку вокруг частей, которые вы хотите переместить (подумайте об этом внимательно) и используйте код Apple здесь: developer.apple.com/library/content / documentation /… с одной модификацией: используйте UIKeyboardWillShowNotification вместо UIKeyboardDidShowNotification. Это улучшение устранит задержку перед началом прокрутки.

chuckSaldana
12 июня 2018 в 16:55
0

Не очень полезно, если вы хотите разрешить прокрутку при редактировании полей ввода.

Kedar Sukerkar
10 сентября 2019 в 12:02
0

я бы предложил использовать IQKeyboardManager

Fattie
17 октября 2019 в 11:27
0

В наши дни этот ответ вовсе не является решением. Сегодня вы бы никогда не передвинули «рамку», вы просто анимируете ограничение. Это очень просто. Популярный пример - coderhelper.com/a/41808338/294884

iSpain17
24 мая 2020 в 10:44
0

Этот ответ устарел с iOS 13.

avatar
3 ноября 2021 в 07:41
0

Вот мое решение «Только расширение UITextView», основанное на решении Пола Хадсона @twostraws (привет ему и всем авторам подобных ответов здесь).

import UIKit

extension UITextView {
    
    func adjustableForKeyboard() {
        let notificationCenter = NotificationCenter.default
        
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }
    
    @objc private func adjustForKeyboard(notification: Notification) {
        guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {
            return
        }

        let keyboardScreenEndFrame = keyboardValue.cgRectValue
        let keyboardViewEndFrame = convert(keyboardScreenEndFrame, from: window)
        
        if notification.name == UIResponder.keyboardWillHideNotification {
            contentInset = .zero
        } else {
            contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height - safeAreaInsets.bottom, right: 0)
        }

        scrollIndicatorInsets = contentInset
        scrollRangeToVisible(selectedRange)
    }
}

Использование:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        textView.adjustableForKeyboard()
    }
avatar
6 июля 2021 в 06:25
1

Получил ссылку из ответа Дюны Багги. Для прокрутки вверх в соответствии с TextField положением . Bcz существующий ответ прокручивает весь вид экрана вместо этого, мне нужно прокрутить вид в соответствии с рамкой textField

  • KeyBoardWillShow
 @objc func keyboardWillShow(notification: NSNotification) {
        
        guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
            
            // if keyboard size is not available for some reason, don't do anything

            return
        }
        let keyboardFrame = keyboardSize
        
        let maxheightScreen = self.view.frame
        
        
        if (self.txtEmail.frame.origin.y + ((self.txtEmail.superview)!.frame.maxY) + keyboardSize.height) >= maxheightScreen.size.height{
            if self.view.frame.origin.y == 0{
                self.view.frame.origin.y -= (keyboardFrame.height - (self.txtEmail.frame.maxY + 120)) // Here i added 120 additional height for my additional view space
            }
        }
        
        
   }
  • КлавиатураБудетСкрыть
  @objc func keyboardWillHide(notification: NSNotification) {
      
        guard let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
                // if keyboard size is not available for some reason, don't do anything
                 
                return
             }
        
        let keyboardFrame = keyboardSize
        
        if self.view.frame.origin.y != 0{
            self.view.frame.origin.y += (keyboardFrame.height - (self.txtEmail.frame.maxY + 120))
        }

    }
avatar
16 июня 2021 в 10:46
1

// вам не нужно такое количество кода только для простого // вместо этого используйте этот код в делегате приложения перед возвратом в didFinishLaunchingWithOptions

    IQKeyboardManager.shared().isEnabled = true
    IQKeyboardManager.shared().shouldResignOnTouchOutside = true
    IQKeyboardManager.shared().isEnableAutoToolbar = false

// и не забудьте установить этот под

 pod 'IQKeyboardManager'
avatar
alexgophermix
20 июня 2020 в 09:12
3

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

MessageComposerView


(источник: thegameengine.org)

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

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

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

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

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

avatar
20 июня 2020 в 09:12
-1

SwiftUI с использованием ViewModifier

Вы можете использовать ViewModifier в swiftui намного проще

import SwiftUI
import Combine

struct KeyboardAwareModifier: ViewModifier {
    @State private var keyboardHeight: CGFloat = 0

    private var keyboardHeightPublisher: AnyPublisher<CGFloat, Never> {
        Publishers.Merge(
            NotificationCenter.default
                .publisher(for: UIResponder.keyboardWillShowNotification)
                .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue }
                .map { $0.cgRectValue.height },
            NotificationCenter.default
                .publisher(for: UIResponder.keyboardWillHideNotification)
                .map { _ in CGFloat(0) }
       ).eraseToAnyPublisher()
    }

    func body(content: Content) -> some View {
        content
            .padding(.bottom, keyboardHeight)
            .onReceive(keyboardHeightPublisher) { self.keyboardHeight = $0 }
    }
}

extension View {
    func KeyboardAwarePadding() -> some View {
        ModifiedContent(content: self, modifier: KeyboardAwareModifier())
    }
}

И на ваш взгляд

struct SomeView: View {
    @State private var someText: String = ""

    var body: some View {
        VStack {
            Spacer()
            TextField("some text", text: $someText)
        }.KeyboardAwarePadding()
    }
}

KeyboardAwarePadding() автоматически добавит отступ в вашем представлении, это более элегантно.

avatar
Orçun Deniz
3 мая 2020 в 22:51
1

Я разработал структуру для решения этой проблемы лучше и опубликовал ее сейчас. Это не только для UITextField и UITextView, он работает для любого пользовательского UIView, который принимает протокол UITextInput, например UITextField и UITextView, и предлагает множество полезных функций. Вы можете установить его через Carthage, CocoaPods или Swift Package Manager.

ODScrollView GitHub

ODScrollView Medium

ODScrollView - это просто UIScrollView, который автоматически перемещает редактируемые текстовые области, такие как UITextField и UITextView, по вертикали в зависимости от видимости клавиатуры, чтобы улучшить взаимодействие с пользователем.

Функции

  • Автоматически перемещает UIViews первого респондента, которые принимают протокол UITextInput, вверх / вниз, когда клавиатура появляется / исчезает, например UITextField, UITextView, UISearchTextField или любой пользовательский UIView, который принимает протокол UITextInput.
    • Обратите внимание, что если кадр UITextInput НЕ соответствует оставшейся области между ODScrollView и клавиатурой, то ODScrollView регулирует UITextInput на основе положения курсора, а не кадра. В таких случаях можно использовать функцию «trackTextInputCursor». Пример
  • Предел регулировки можно применять для каждого UITextInput отдельно для настройки направления регулировки .Top и .Bottom. 20 CGFloat по умолчанию.

  • Регулировка может быть включена / отключена для каждого UITextInput отдельно. по умолчанию true.

  • Директива настройки - .Top, .Center, .Bottom - может применяться для каждого UITextInput отдельно. .Bottom по умолчанию. Пример

  • Параметры настройки определяют, как настраивается ODScrollView. .Всегда по умолчанию.
    • .Всегда: ODScrollView всегда регулирует UITextInput, который помещается в любом месте ODScrollView, независимо от того, перекрывается ли UITextInput с отображаемой клавиатурой. Пример
    • .IfNeeded: ODScrollView корректирует UITextInput только в том случае, если он перекрывается с показанной клавиатурой. Пример
  • Помимо UIScrollView.keyboardDismissModes, клавиатуру можно закрыть, коснувшись UIView, который предоставляется ODScrollViewDelegate. После закрытия клавиатуры ODScrollView может вернуть исходное положение. по умолчанию nil и false. Пример

Использование

1 - Первое, что вам нужно сделать, это правильно настроить ODScrollView и его представление содержимого. Поскольку ODScrollView - это просто UIScrollView, вы можете реализовать ODScrollView так же, как и для UIScrollView. Вам решать, создавать ODScrollView с помощью раскадровки или программно.

Если вы создаете ODScrollView программно, вы можете продолжить с шага 4.

Предлагаемый способ создания UIScrollView в раскадровке

- If you are using Content Layout Guide and Frame Layout Guide:
    1.1 - scrollView: Place UIScrollView anywhere you want to use.  
    1.2 - contentView: Place UIView inside scrollView.
    1.3 - Set contentView's top, bottom, leading and trailing constraints to Content Layout Guide's constraints.
    1.4 - Set contentView's width equal to Frame Layout Guide's width.
    1.5 - Set contentView's height equal to Frame Layout Guide's height or set static height which is larger than scrollView's height.
    1.6 - Build your UI inside contentView.

- If you are NOT using Content Layout Guide and Frame Layout Guide:
    1.1 - scrollView: Place UIScrollView anywhere you want to use.  
    1.2 - contentView: Place UIView inside scrollView.
    1.3 - Set contentView's top, bottom, leading and trailing constraints to 0.
    1.4 - Set contentView's width equal to scrollView's width.
    1.5 - Set contentView's height equal to scrollView's superview's height or set static height which is larger than scrollView's height.
    1.6 - Build your UI inside contentView.

2 - Измените класс scrollView с UIScrollView на ODScrollView в инспекторе удостоверений на Storyboard.

3 - Создание IBOutlets для scrollView и contentView на ViewController.

4 - Вызов следующих методов внутри ViewDidLoad () на ViewController:

override func viewDidLoad() {
    super.viewDidLoad()

    //ODScrollView setup
    scrollView.registerContentView(contentView)
    scrollView.odScrollViewDelegate = self
}  

5 - Необязательно: вы по-прежнему можете использовать функции UIScrollView:

override func viewDidLoad() {
    super.viewDidLoad()

    //ODScrollView setup
    scrollView.registerContentView(contentView)
    scrollView.odScrollViewDelegate = self

    // UIScrollView setup
    scrollView.delegate = self // UIScrollView Delegate
    scrollView.keyboardDismissMode = .onDrag // UIScrollView keyboardDismissMode. Default is .none.

    UITextView_inside_contentView.delegate = self
}

6 - Принять ODScrollViewDelegate из ViewController и выбрать параметры ODScrollView:

extension ViewController: ODScrollViewDelegate {

    // MARK:- State Notifiers: are responsible for notifiying ViewController about what is going on while adjusting. You don't have to do anything if you don't need them.

    // #Optional
    // Notifies when the keyboard showed.
    func keyboardDidShow(by scrollView: ODScrollView) {}

    // #Optional
    // Notifies before the UIScrollView adjustment.
    func scrollAdjustmentWillBegin(by scrollView: ODScrollView) {}

    // #Optional
    // Notifies after the UIScrollView adjustment.
    func scrollAdjustmentDidEnd(by scrollView: ODScrollView) {}

    // #Optional
    // Notifies when the keyboard hid.
    func keyboardDidHide(by scrollView: ODScrollView) {}

    // MARK:- Adjustment Settings

    // #Optional
    // Specifies the margin between UITextInput and ODScrollView's top or bottom constraint depending on AdjustmentDirection
    func adjustmentMargin(for textInput: UITextInput, inside scrollView: ODScrollView) -> CGFloat {
        if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {
            return 20
        } else {
            return 40
        }
    }

    // #Optional
    // Specifies that whether adjustment is enabled or not for each UITextInput seperately.
    func adjustmentEnabled(for textInput: UITextInput, inside scrollView: ODScrollView) -> Bool {
        if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {
            return true
        } else {
            return false
        }
    }


    // Specifies adjustment direction for each UITextInput. It means that  some of UITextInputs inside ODScrollView can be adjusted to the bottom, while others can be adjusted to center or top.
    func adjustmentDirection(selected textInput: UITextInput, inside scrollView: ODScrollView) -> AdjustmentDirection {
        if let textField = textInput as? UITextField, textField == self.UITextField_inside_contentView {
            return .bottom
        } else {
            return .center
        }
    }

    /**
     - Always : ODScrollView always adjusts the UITextInput which is placed anywhere in the ODScrollView.
     - IfNeeded : ODScrollView only adjusts the UITextInput if it overlaps with the shown keyboard.
     */
    func adjustmentOption(for scrollView: ODScrollView) -> AdjustmentOption {
        .Always
    }

    // MARK: - Hiding Keyboard Settings

    /**
     #Optional

     Provides a view for tap gesture that hides keyboard.

     By default, keyboard can be dismissed by keyboardDismissMode of UIScrollView.

     keyboardDismissMode = .none
     keyboardDismissMode = .onDrag
     keyboardDismissMode = .interactive

     Beside above settings:

     - Returning UIView from this, lets you to hide the keyboard by tapping the UIView you provide, and also be able to use isResettingAdjustmentEnabled(for scrollView: ODScrollView) setting.

     - If you return nil instead of UIView object, It means that hiding the keyboard by tapping is disabled.
     */
    func hideKeyboardByTappingToView(for scrollView: ODScrollView) -> UIView? {
        self.view
    }

    /**
     #Optional

     Resets the scroll view offset - which is adjusted before - to beginning its position after keyboard hid by tapping to the provided UIView via hideKeyboardByTappingToView.

     ## IMPORTANT:
     This feature requires a UIView that is provided by hideKeyboardByTappingToView().
     */
    func isResettingAdjustmentEnabled(for scrollView: ODScrollView) -> Bool {
        true
    }
}

7 - Необязательно: вы можете настроить ODScrollView, когда курсор перекрывается с клавиатурой при вводе многострочного UITextInput. trackTextInputCursor (для UITextInput) должен вызываться функциями UITextInput, которые запускаются при вводе.

/**
## IMPORTANT:
This feature is not going to work unless textView is subView of _ODScrollView
*/
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
       _ODScrollView.trackTextInputCursor(for textView)
   return true
}
avatar
DK_
29 декабря 2019 в 11:38
273

На самом деле лучше всего использовать реализацию 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)
zakdances
28 мая 2012 в 22:42
0

Разве не лучшим решением было бы отрегулировать размер прокрутки так, чтобы его высота соответствовала верхней части клавиатуры?

8vius
14 июня 2012 в 16:04
0

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

DK_
5 июля 2012 в 10:38
0

@ 8vius Убедитесь, что вы не инвертировали исходную точку обзора? В зависимости от того, что определено как origin (0,0), это изменит логику.

mblackwell8
9 мая 2013 в 04:48
2

В ситуациях, когда представление прокрутки не заполняет экран, aRect должен быть установлен на рамку представления прокрутки

makaed
17 марта 2014 в 17:22
0

@DK_ Я следил за реализацией Apple и изменил предоставленную вами часть. Однако у меня это не работает. Я вижу, что мое скрытое текстовое поле перемещается очень немного вверх, но далеко не видно. Есть идеи, где может быть проблема?

DK_
18 марта 2014 в 18:22
0

@Makaed Я бы дважды проверил ваши рамки просмотра.

makaed
19 марта 2014 в 01:06
0

@DK_ Кажется, там хорошо. У меня есть несколько текстовых полей в общем виде прокрутки (не подклассифицировал его, просто создал для него выход). Это не имеет значения, правда?

htafoya
15 апреля 2014 в 17:16
2

Разве вам не нужно, чтобы CGPoint origin = activeField.frame.origin + activeField.frame.size.height ?, потому что вы хотите, чтобы отображалось все текстовое поле, и если в нем видны только некоторые пиксели, код не будет вводить условие.

htafoya
15 апреля 2014 в 17:20
0

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

Andrew
27 апреля 2014 в 09:47
1

Это решение не работает в альбомной ориентации - текстовое поле вылетает за верхнюю часть окна просмотра. iPad с iOS 7.1.

hris.to
25 июня 2014 в 08:56
0

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

Chris Nolet
19 июля 2014 в 01:34
0

Для пункта 2 проще всего использовать: [self.scrollView scrollRectToVisible:activeField.frame animated:YES];

Endareth
13 ноября 2014 в 02:06
4

Для лучшей поддержки iOS 8 я бы предложил использовать UIKeyboardFrameEndUserInfoKey вместо UIKeyboardFrameBeginUserInfoKey при получении размера клавиатуры, так как это подберет такие вещи, как пользовательские изменения клавиатуры и включение / выключение прогнозируемого текста.

Morten Holmgaard
23 января 2015 в 07:32
1

@ Егор: ​​Ваше исправление позволяет улучшить его работу, но последняя строка должна быть обратной: self.scrollView.contentOffset = self.currentSVoffset;

Egor
23 января 2015 в 07:38
0

@MortenHolmgaard Конечно, ты прав. Это была ошибка при копировании кода из моего проекта.

David Cespedes
8 марта 2015 в 01:53
0

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

CularBytes
29 сентября 2015 в 07:57
0

Сентябрь 2015: Я реализовал его с помощью swift, он правильно перемещает представление вверх, когда начинаю редактировать текстовое представление, однако, когда я прокручиваю ScrollView, пока клавиатура все еще присутствует, он сбрасывается до исходного, тем самым скрывая текстовое представление позади снова клавиатуру. Кроме того, когда я уже немного прокрутил вниз, он больше не будет прокручиваться вверх, когда начну редактировать текстовое представление. Я попробую ответить ниже: coderhelper.com/a/17707278/2901207

avatar
13 декабря 2019 в 06:52
-1

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

Для этого вы должны использовать Scrollview. Предположим, это ваша иерархия UIView. ContainerView -> ScrollView -> ContentView -> Ваше представление.

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

Но этот подход должен быть добавлен на каждый контроллер, где когда-либо UIView необходимо переключить. Я использовал модуль TPKeyboardAvoiding. Это надежно и легко справляется с изменением UIView для всех возможных случаев, если вы используете Scrollview, TableView или CollectionView. Вам просто нужно передать класс в "прокручиваемое представление".

Как показано ниже

demo Image

Вы можете изменить этот класс, если у вас tableview, на TPKeyboardAvoidingTableView. Вы можете найти полностью работающий проект Ссылка на проект

Этого надежного подхода я придерживался при разработке. Надеюсь, это поможет!

avatar
deepti
22 ноября 2019 в 00:57
7

Вам необходимо программно добавить scrollview с определенным размером кадра. Вы должны добавить 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, ширины и высоты.

avatar
Arvind Kumar
22 ноября 2019 в 00:55
10

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

https://github.com/hackiftekhar/IQKeyboardManager

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

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

avatar
Mojtaba Hosseini
10 октября 2019 в 20:35
3

- SwiftUI

Показать только активные TextField

Это переместит представление достаточно, чтобы избежать скрытия только активного TextField. When each TextField is clicked, the view is only moved up enough to make the clicked text field visible.

struct ContentView: View {
    @ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 3)
    @State private var name = Array<String>.init(repeating: "", count: 3)

    var body: some View {

        VStack {
            Group {
                Text("Some filler text").font(.largeTitle)
                Text("Some filler text").font(.largeTitle)
            }

            TextField("text #1", text: $name[0], onEditingChanged: { if $0 { self.kGuardian.showField = 0 } })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[0]))

            TextField("text #2", text: $name[1], onEditingChanged: { if $0 { self.kGuardian.showField = 1 } })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[1]))

            TextField("text #3", text: $name[2], onEditingChanged: { if $0 { self.kGuardian.showField = 2 } })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[2]))

            }.offset(y: kGuardian.slide).animation(.easeInOut(duration: 0.25))
    }

}

Показать все TextField s

Это перемещает все textField вверх, если для любого из них появляется клавиатура. Но только при необходимости. Если клавиатура не скрывает текстовые поля, они не будут перемещаться. When the keyboard is opened, the 3 textfields are moved up enough to keep then all visible

struct ContentView: View {
    @ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 1)
    @State private var name = Array<String>.init(repeating: "", count: 3)

    var body: some View {

        VStack {
            Group {
                Text("Some filler text").font(.largeTitle)
                Text("Some filler text").font(.largeTitle)
            }

            TextField("enter text #1", text: $name[0])
                .textFieldStyle(RoundedBorderTextFieldStyle())

            TextField("enter text #2", text: $name[1])
                .textFieldStyle(RoundedBorderTextFieldStyle())

            TextField("enter text #3", text: $name[2])
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[0]))

        }.offset(y: kGuardian.slide).animation(.easeInOut(duration: 0.25))
    }

}

В обоих примерах используются одни и те же общие коды: GeometryGetter и KeyboardGuardian На основе @kontiki

GeometryGetter

Это представление, которое поглощает размер и положение своего родительского представления. Инкапсулируйте здесь описание. Для этого он вызывается внутри модификатора .background. Это очень мощный модификатор, а не просто способ украсить фон вида. При передаче представления в .background (MyView ()) MyView получает измененное представление в качестве родительского. Использование GeometryReader - это то, что позволяет представлению знать геометрию родительского объекта.

Например: Text("hello").background(GeometryGetter(rect: $bounds)) заполнит границы переменных размером и положением текстового представления и с использованием глобального координатного пространства.

struct GeometryGetter: View {
    @Binding var rect: CGRect

    var body: some View {
        GeometryReader { geometry in
            Group { () -> AnyView in
                DispatchQueue.main.async {
                    self.rect = geometry.frame(in: .global)
                }

                return AnyView(Color.clear)
            }
        }
    }
}

Обратите внимание, что DispatchQueue.main.async позволяет избежать возможности изменения состояния представления во время его рендеринга.

KeyboardGuardian

Назначение KeyboardGuardian - отслеживать события отображения / скрытия клавиатуры и вычислять, на сколько места необходимо сместить представление.

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

import SwiftUI
import Combine

final class KeyboardGuardian: ObservableObject {
    public var rects: Array<CGRect>
    public var keyboardRect: CGRect = CGRect()

    // keyboardWillShow notification may be posted repeatedly,
    // this flag makes sure we only act once per keyboard appearance
    public var keyboardIsHidden = true

    @Published var slide: CGFloat = 0

    var showField: Int = 0 {
        didSet {
            updateSlide()
        }
    }

    init(textFieldCount: Int) {
        self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)

        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardDidHide(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)

    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    @objc func keyBoardWillShow(notification: Notification) {
        if keyboardIsHidden {
            keyboardIsHidden = false
            if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
                keyboardRect = rect
                updateSlide()
            }
        }
    }

    @objc func keyBoardDidHide(notification: Notification) {
        keyboardIsHidden = true
        updateSlide()
    }

    func updateSlide() {
        if keyboardIsHidden {
            slide = 0
        } else {
            let tfRect = self.rects[self.showField]
            let diff = keyboardRect.minY - tfRect.maxY

            if diff > 0 {
                slide += diff
            } else {
                slide += min(diff, 0)
            }

        }
    }
}
avatar
6 июля 2019 в 21:16
2

Swift 5

в viewDidLoad или viewDidAppear добавьте метод addKeyboardObservers .

fileprivate func addKeyboardObservers(){
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

fileprivate func removeKeyboardObservers(){
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}


@objc fileprivate func keyboardWillHide(_ notification: Notification){
    if (window == nil) {return}
    guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}

   scrollView.contentInset.bottom = .zero
}


@objc fileprivate func keyboardWillShow(_ notification: Notification){
    if (window == nil) {return}
    if UIApplication.shared.applicationState != .active { return }

    // keyboard height
    guard let height = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height else {return}
    // keyboard present animation duration
    guard let duration = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double) else {return}

   scrollView.contentInset.bottom = height
}

не забудьте удалить наблюдателей при деинициализации или исчезновении

    self.removeKeyboardObservers()
Jay Lee
26 июля 2019 в 04:21
1

В документации Apple на addObserver:selector:name:object: говорится: «Если ваше приложение нацелено на iOS 9.0 и новее или macOS 10.11 и новее, вам не нужно отменять регистрацию наблюдателя в его методе освобождения».

avatar
Satnam Sync
5 июля 2019 в 08:46
93

Для 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()
}

Для Swift 4, 4.2, 5: Изменить

self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
От

до

self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)

Последнее замечание об этой реализации: если вы поместите другой контроллер представления в стек, когда отображается клавиатура, это создаст ошибку, при которой представление возвращается обратно в его центральный фрейм, но смещение клавиатуры не сбрасывается. Например, ваша клавиатура является первым респондентом для nameField, но затем вы нажимаете кнопку, которая помещает ваш Help View Controller в ваш стек. Чтобы исправить ошибку смещения, обязательно вызовите nameField.resignFirstResponder () перед выходом из контроллера представления, убедившись, что также вызывается метод делегата textFieldDidEndEditing. Я делаю это в методе viewWillDisappear.

levibostian
10 мая 2016 в 18:10
3

SwiftLint не понравился self.view.frame = CGRectOffset(self.view.frame, 0, movement), поэтому я изменил эту строку на self.view.frame.offsetInPlace(dx: 0, dy: movement)

Asinox
14 января 2018 в 20:22
2

Swift 4 измените self.view.frame = CGRectOffset (self.view.frame, 0, движение) на self.view.frame.offsetBy (dx: 0, dy: движение)

Josh Wolff
5 июля 2019 в 08:32
0

К вашему сведению, чтобы это сработало, вам нужно установить. self.view.frame = self.view.frame.offsetBy (dx: 0, dy: движение)

avatar
5 апреля 2019 в 10:00
2

Используя IQKeyboardManager, UITextField и UITextView автоматически прокручиваются при появлении клавиатуры. Ссылка Git: https://github.com/hackiftekhar/IQKeyboardManager.

пакет: pod 'IQKeyboardManager' # iOS8 и выше

pod 'IQKeyboardManager', '3.3.7' # iOS7

avatar
jayesh mardiya
15 января 2019 в 00:44
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);
}
avatar
Sourabh Sharma
15 января 2019 в 00:43
21

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

- (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];
}
avatar
26 сентября 2018 в 18:28
0

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

override var inputAccessoryView: UIView? {
    return <yourTextField>
}
avatar
12 сентября 2018 в 08:16
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)
}
avatar
24 мая 2018 в 13:29
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)
}
avatar
Bruce Lee
17 мая 2018 в 17:55
-9

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

avatar
dmani ms
17 мая 2018 в 09:07
-2

Обратитесь к следующему

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
    }

}
avatar
ZAFAR007
28 апреля 2018 в 10:37
14

Swift 4 .

Вы можете легко перемещаться вверх и вниз UITextField или UIView с UIKeyBoard с Animation enter image description here

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
    }

}
Houman
18 августа 2018 в 17:27
2

Практически идеально. Однако на iPhone X между клавиатурой и текстовым полем наблюдается странный разрыв.

avatar
18 апреля 2018 в 10:16
0

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

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

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

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

avatar
cbranch
17 декабря 2017 в 10:45
63

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

Leo
29 декабря 2019 в 21:11
0

Это не UIScrollView, который неявно прокручивает отредактированный UITextField в поле зрения, это UITextField, который вызывает частный метод [UITextField scrollTextFieldToVisibleIfNecessary], который, в свою очередь, вызывает [UIScrollView scrollRectToVisible] при вызове [UITextField becomeFirstResponder]. См. github.com/leopatras/ios_textfields_on_scrollview. Если ограничения и контроллеры представления настроены правильно, на самом деле нет необходимости явно вызывать scrollRectToVisible (по крайней мере, с IOS 11).

avatar
Harminder Singh
3 декабря 2017 в 13:34
0

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

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

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

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

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

avatar
Shiun
31 октября 2017 в 12:58
447

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

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

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

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

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

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

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

Martin Wickman
20 апреля 2011 в 21:26
3

Отлично, но две проблемы: 1. UIKeyboardBoundsUserInfoKey устарел. 2. keyboardSize находится в "экранных координатах", поэтому ваши вычисления viewFrame завершатся ошибкой, если кадр будет повернут или масштабирован.

sottenad
30 июля 2011 в 20:51
21

@Martin Wickman - используйте CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; вместо устаревшего UIKeyboardBoundsUserInfoKey

gyozo kudor
2 августа 2011 в 08:13
0

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

Philip Regan
17 апреля 2012 в 02:39
0

Это не работает как запись для iOS 5. Либо чего-то не хватает в описании реализации или коде, либо что-то из комментариев заставляет его работать, но я не мог заставить его работать должным образом в iOS 5. Фактически, собственное Apple документы не обновлялись с iOS 3.

user517491
19 апреля 2012 в 13:07
1

Привет, я сделал то же самое, но текстовое представление перемещается вверх только тогда, когда пользователь начинает печатать? Это ожидаемое поведение или я что-то упускаю?

user517491
19 апреля 2012 в 13:14
0

@Shiun Привет, я сделал то же самое, но текстовое представление перемещается вверх только тогда, когда пользователь начинает печатать? Это ожидаемое поведение или я что-то упускаю?

newton_guima
2 мая 2012 в 23:33
0

@Shiun, вы также должны удалить себя в качестве наблюдателя в методе dealloc ... люди часто путают viewDidUnload как противоположность viewDidLoad ... viewDidUnload вызывается только тогда, когда есть предупреждение о памяти ... поэтому он может никогда не вызываться, вместо этого в какой-то момент обязательно будет вызван dealloc.

j7nn7k
24 мая 2012 в 08:09
3

[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size должно быть [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size. Хотя отличное решение!

Tim Büthe
21 июня 2012 в 20:45
0

Как говорит @djaqeel, было бы здорово, если бы прокрутка происходила, как только поля получают фокус, а не когда начинаете печатать. Во-вторых, было бы здорово вернуться к началу или даже в исходное положение, когда клавиатура скрыта.

Craig B
31 октября 2012 в 19:45
0

Хорошо, еще пара вещей. Из этого словаря userInfo вы можете получить продолжительность и кривую анимации с помощью следующих ключей: UIKeyboardAnimationDurationUserInfoKey и UIKeyboardAnimationCurveUserInfoKey. Вы обязательно должны использовать их вместо жесткого кодирования !!!

AlexChaffee
12 февраля 2013 в 23:51
1

Мне нравится ваше решение, но я думаю, что могу сделать его еще проще: не беспокойтесь о материалах Notification Observer; вместо этого вызывайте правильные процедуры анимации внутри соответствующих методов делегата - для UITextView это textViewDidBeginEditing и textViewDidEndEditing.

Mxyk
5 марта 2013 в 19:32
0

@glenc Что ты имеешь в виду? Как мне это сделать (не могли бы вы предоставить образец кода)? Потому что это работает и для меня, за исключением случаев, когда iPad находится в альбомной ориентации.

dwlz
3 января 2014 в 16:05
1

Это правильный ответ. Другой ответ, который в настоящее время отмечен как правильный, имеет размер клавиатуры, закрепленный на 80, что очень хорошо может меняться в iOS от версии к версии. Этот ответ подходит для этой ситуации.

tounaobun
6 февраля 2015 в 07:01
0

Требуется свойство keyboardIsShown, иначе нижняя часть contentInset вашего UIScrollview станет больше, когда вы нажмете кнопку глобуса на клавиатуре (изменить ввод).

David Cespedes
8 марта 2015 в 04:23
0

Это не верно для меня "Уведомление клавиатуры будет срабатывать, даже если клавиатура уже отображается". Я делаю что-то неправильно? Я работаю с Xcode 6.1.1 на iOS 7 и 8. Автоматическая раскладка отключена.

Hemang
26 марта 2015 в 06:37
0

@DavidCespedes, какое уведомление запускается? Если он уже виден, должен позвонить keyboardWillHide:.

David Cespedes
27 марта 2015 в 17:24
0

@hagile в ответе говорят, что «Уведомление с клавиатуры будет срабатывать, даже когда клавиатура уже отображается». Это не правда. Он будет срабатывать только тогда, когда он будет показан, но если он уже находится на экране, он не будет и не должен запускать эту keyboardWillShow снова, как это уже показано. Думаю, это работает так, начиная с iOS 6. Раньше он запускал уведомление независимо от того, была ли клавиатура уже отображена.

CyberMoai
6 мая 2017 в 01:40
0

Очень важно: используйте UIKeyboardFrameEndUserInfoKey вместо UIKeyboardFrameBeginUserInfoKey. Имеет значение при повороте обзора.

avatar
1 августа 2017 в 01:08
4

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

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

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

avatar
7 июля 2017 в 09:05
2

Простое решение для прокрутки с текстовыми полями приведено ниже, нет необходимости в каких-либо ограничениях или активном текстовом поле и т. Д.

 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

        }
avatar
Martin Ullrich
24 июня 2017 в 09:40
65

Уже есть много ответов, но все же ни одно из вышеперечисленных решений не имело всех причудливых элементов позиционирования, необходимых для «идеальной» безошибочной, обратной совместимости и без мерцания анимации. (ошибка при одновременной анимации кадра / границ и 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];
}
Lucien
6 июня 2013 в 12:40
0

Значительные улучшения ответа @Shiun. Но после того, как клавиатура исчезла, вид не возвращается в 1-ю позицию. Это по-прежнему отличная работа :)

xaphod
2 июня 2017 в 20:41
2

Спасибо, это лучшее решение для меня в 2017 году. Обратите внимание, что вам не нужно самостоятельно отслеживать FocusControl, вы можете определить это с помощью UIApplication.shared.sendAction(...). Вот версия вашего ответа Swift 3 (минус часть willHide) с реализованным sendAction: gist.github.com/xaphod/7aab1302004f6e933593a11ad8f5a72d

Martin Ullrich
25 июня 2017 в 16:33
0

@xaphod в моем случае мне нужно было сосредоточить больше элементов управления - например, кнопка под полем ввода. но да, этому коду уже 4 года, и он может быть улучшен.

X.Y.
26 января 2019 в 17:42
0

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

avatar
xaphod
23 мая 2017 в 12:34
0

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

См.: Ограничение автоматического раскладки - клавиатура

Вот мой код:

.m файл:

// 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
avatar
27 марта 2017 в 21:22
0

Для Swift Developer, использующего Swift 3, вот репо 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's 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)
    }
}
avatar
6 марта 2017 в 08:28
6

Просто добавьте это в файл модуля -> pod 'IQKeyboardManager'

Вот и все, вся клавиатура, прокрутка и все остальное!

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

У него есть расширение, которое обрабатывает отображение текстовых полей, сдвиг экрана, стрелки вперед и назад при наличии нескольких текстовых полей.

Он также имеет настраиваемую кнопку «Готово», которую можно удалить.

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

avatar
27 февраля 2017 в 08:24
2

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's 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
}
}
avatar
17 февраля 2017 в 13:36
1

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

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

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

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

А затем вызовите указанный ниже метон в методе делегата.

 - (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];
    }
}
avatar
18 ноября 2016 в 07:44
-3

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

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

        }

    }
EJoshuaS - Reinstate Monica
10 января 2017 в 04:53
0

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

avatar
seggy
17 ноября 2016 в 06:57
3

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

  - (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];
    }
avatar
2 ноября 2016 в 15:47
0

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

П.С. Я не использую 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
}
avatar
27 октября 2016 в 06:01
2

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

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

avatar
22 октября 2016 в 07:32
0

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

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

IQKeyboard

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

Спасибо

Может быть, это будет полезно.

avatar
11 октября 2016 в 10:08
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);
Alp Altunel
23 февраля 2018 в 22:37
0

это отлично сработало с файлом xib, отображаемым как всплывающее окно

avatar
sumanthkodi
4 октября 2016 в 15:21
247

В 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)
    }
Andre Cytryn
8 августа 2012 в 22:20
1

почему бы не использовать [UIView animateWithDuration: animations:^{ }];?

Hammer
10 октября 2014 в 03:57
2

это работает хорошо, хотя const int motionDistance = -130; // настраиваем по мере необходимости, чтобы сделать его более гибким

user3344977
20 марта 2015 в 02:08
0

@UserDev Это отлично работает как на iOS 7, так и на 8. Панель навигации не является частью представления, которое анимируется в коде.

James Perih
9 мая 2015 в 02:13
7

Невероятно просто для небольших реализаций. Никаких проблем с ScrollViews и Ambiguous auto-layout.

Jabbar
23 февраля 2016 в 11:45
0

Фактически, он также работает для нескольких текстовых полей. Спасибо

andreas
26 февраля 2016 в 15:11
0

Мне нравится простота этого ответа. Когда я перешел на ограничения (iOS> 8), у меня тоже начались проблемы. Я расширил этот ответ в новом посте @Gannicus, чтобы он снова заработал.

Andres Canella
2 марта 2016 в 19:04
0

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

Burak
8 августа 2016 в 14:54
0

Для тех, кто использует storyboard и пытается заставить его работать, но не может, просто убедитесь, что self.view имеет ведущий , верхний и конечный constraints>. В противном случае, вероятно, не получится.

stk
23 октября 2016 в 15:16
4

Эм ... вы вообще не используете параметр textField. Зачем тогда использовать его как параметр функции? Кроме того, вы также можете использовать тернарный оператор в Swift. Делает код менее разговорчивым.

bvmobileapps
21 марта 2017 в 22:23
1

Если цвет фона представления не черный, убедитесь, что вы установили цвет окна, соответствующий вашему представлению, чтобы пользователь не видел за ним. т.е. self.window.backgroundColor = [UIColor whiteColor];

Federico Picci
19 апреля 2017 в 10:41
0

Требуется _ в параметрах метода для соответствия делегированию и тихому предупреждению func textFieldDidBeginEditing(_ textField: UITextField)

avatar
lakersgonna3peat
3 августа 2016 в 06:07
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];
}
Adam Johns
8 августа 2014 в 21:03
0

Я не понимаю, для чего нужен этот код? Когда отображается клавиатура, viewWillAppear не вызывается. И reloadData не делает видимыми скрытые строки.

avatar
Nicolas Marchand
3 августа 2016 в 06:06
23

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

-(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];
    }
}
avatar
17 июля 2016 в 18:51
4

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

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

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

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

// UIKeyboardWillHideNotification
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    self.scrollView.contentInset = contentInsets;
    self.scrollView.scrollIndicatorInsets = contentInsets;
}
Leo
29 декабря 2019 в 21:47
0

В этом суть! Во многих примерах я здесь пытаюсь установить contentOffset или scrollRectToVisible undec. UITextField прокручивается до [UITextField becomeFirstResponder]. Это могут предотвратить неоднозначные размеры содержимого для UIScrollView или явные вызовы одного из методов прокрутки в представление. См. Рабочую демонстрацию с использованием этого простого подхода на github.com/leopatras/ios_textfields_on_scrollview. Документ Apple сбивает с толку, потому что в нем упоминается scrollRectToView без указания, что он вообще не нужен для UITextField.

avatar
8 июля 2016 в 09:23
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;
avatar
30 мая 2016 в 10:25
2
  1. Загрузите TPKeyBoardAvoiding по этой ссылке: https://github.com/michaeltyson/TPKeyboardAvoiding.
  2. Разверните заархивированную папку и найдите папку TPKeyboardAvoiding.
  3. Выберите все файлы .h и .m и перетащите их в свой проект. Убедитесь, что при необходимости копировать элементы отмечены галочкой.
  4. Перетащите UIScrollView на StoryBoard и свяжите его с TPKeyboardAvoidingScrollView.
  5. Теперь вы можете добавлять элементы пользовательского интерфейса в верхнюю часть области прокрутки. Обратите внимание, что этот класс обнаруживает касания элементов пользовательского интерфейса даже после перетаскивания 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
    }

Добавить делегатов текстового поля.

//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);
}
avatar
Mohammad Kamran Usmani
2 мая 2016 в 12:11
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); 
}
avatar
Ganesh Guturi
2 мая 2016 в 12:08
4

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

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

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

avatar
user436179
2 мая 2016 в 12:06
18

@ user271753

Чтобы вернуть исходное изображение, добавьте:

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
   [textField resignFirstResponder];
   [self setViewMovedUp:NO];
   return YES;
}
avatar
23 апреля 2016 в 18:33
2

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

Вот мой подход (немного измененный способ 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;
}
avatar
22 марта 2016 в 10:23
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 - смещение.

avatar
iDev
18 марта 2016 в 04:45
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];
}
avatar
17 марта 2016 в 12:20
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. Выбор за вами.

avatar
26 февраля 2016 в 15:08
2

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

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

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


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

@IBOutlet var viewConstraint: NSLayoutConstraint!

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

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

}
avatar
24 февраля 2016 в 10:46
2

Это будет работать отлично. Вид прокрутки автоматически регулируется положением текстового поля. Я уверен, что вы будете чувствовать себя хорошо

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];
}
avatar
16 февраля 2016 в 08:58
7

Swift 2.0:

Добавьте UIScrollView и добавьте текстовые поля поверх него. Сделайте ссылки на раскадровку 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)

            })
        }
    }
avatar
22 января 2016 в 18:29
2

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

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

Надлежащее использование: У него есть конкретная реализация для UITextField и UITextView

Ограничение: Он полностью соответствует цели-c, скоро будет доступна быстрая версия.

avatar
8 января 2016 в 06:50
2

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

  • ПРИМЕЧАНИЕ , что: положение и размер таблицы должны быть разумными. например:
    • если позиция y таблицы равна 100 отсчету от нижней части представления, то клавиатура высотой 300 будет перекрывать всю таблицу.
    • если высота таблицы = 10, и текстовое поле в ней должно быть прокручено на 100, когда появляется клавиатура, чтобы быть видимым, то это текстовое поле будет за пределами таблицы.
avatar
19 августа 2015 в 17:45
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];
}

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

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

samthui7
8 января 2016 в 06:58
0

Не думаю, что это лучший вариант. Я думаю @Dheeraj V.S. правильно: это можно сделать легко и автоматически , если это текстовое поле находится в ячейке таблицы (даже если table.scrollable = NO). ПРИМЕЧАНИЕ , что: положение и размер таблицы должны быть разумными. например: - если позиция y таблицы равна 100 отсчету от нижней части представления, то клавиатура высотой 300 будет перекрывать всю таблицу. - если высота таблицы = 10, и текстовое поле в ней должно быть прокручено на 100, когда появляется клавиатура, чтобы быть видимым, то это текстовое поле будет за пределами таблицы.

Ben G
22 марта 2017 в 19:18
0

@ samthui7 Ответ Дираджа работает только в том случае, если вы используете TableViewController, а не только tableview. Это делает его ограничением, которое иногда не подходит.

avatar
22 июля 2015 в 20:07
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);
        }];

    }
}
avatar
6 мая 2015 в 07:33
3

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

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

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

avatar
6 апреля 2015 в 18:54
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()
}
avatar
26 февраля 2015 в 14:34
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];
    }];
}
avatar
13 февраля 2015 в 22:52
0

Я использую Swift и автоматический макет (но не могу комментировать предыдущий ответ 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)
    }

}
avatar
Damien Romito
23 января 2015 в 06:00
3

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

https://github.com/damienromito/VisibleFormViewController

enter image description here

avatar
Homam
6 января 2015 в 05:08
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's visible
        // Your app might not need or want this behavior.
        var aRect = self.view.frame
        aRect.size.height -= kbSize.height;
        if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {
            self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
        }
    }

    // Called when the UIKeyboardWillHideNotification is sent
    func keyboardWillBeHidden (notification: NSNotification) {
        let contentInsets = UIEdgeInsetsZero;
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // MARK: -  Text Field

    func textFieldDidBeginEditing(textField: UITextField) {
        self.activeTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        self.activeTextField = nil
    }

}
Thiha Aung
3 января 2017 в 20:30
0

Правильный ответ, но при использовании TextField и TextView у меня нет проблем. Любая помощь?

Homam
4 января 2017 в 04:00
0

@Thiha Aung, ваши переменные IBOutlet в исходном коде связаны с IB?

Thiha Aung
4 января 2017 в 04:58
0

Да, они тоже подключены. Просто ошибка при использовании UITextView в этой строке: if (! CGRectContainsPoint (aRect, self.activeTextField.frame.origin)) {

Thiha Aung
4 января 2017 в 04:58
0

Означает, что self.activeTextField равен нулю

avatar
Mohd Iftekhar Qurashi
18 декабря 2014 в 16:24
119

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

enter image description here

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

Шаг 2: - Если обнаружены уведомления UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification или UITextViewTextDidBeginEditingNotification, я пытаюсь получить экземпляр topMostViewController из иерархии <80632979 .134 Чтобы правильно раскрыть 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 при загрузке приложения, поэтому каждые <8063297933432> / < будут автоматически перемещаться в соответствии с ожидаемым расстоянием.

Вот и все, что IQKeyboardManager делает для вас с БЕЗ СТРОКИ КОДА действительно !! нужно только перетащить связанный исходный файл в проект. IQKeyboardManager также поддерживает ориентацию устройства , Автоматическое управление UIToolbar , , Keybkey и многое другое.

user3722523
5 ноября 2015 в 17:45
0

Добавить каталог IQKeyBoardManagerSwift в мой проект и не работать. Не могу включить, потому что он не распознается в AppDelegate ...

Brian
5 января 2018 в 23:29
2

это похоже на фишинг, фактическое решение не показано, но вместо этого мы видим рекламу этого парня на GitHub.

avatar
Michael Tyson
16 декабря 2014 в 07:06
102

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

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

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

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

Christopher
18 июня 2012 в 01:36
0

Это оно! Это лучшее, наиболее эффективное и идеальное решение! Он также правильно обрабатывает повороты для прокрутки. При вращении обязательно автоматически измените размер по вертикали, но не закрепляйте его внизу. В моем случае я добавил UITextView к просмотру прокрутки. Большое спасибо!

eselk
11 октября 2012 в 18:34
0

Очень хорошая работа! Конечно, мне лень использовать ваше решение вместо самостоятельного, но мой босс более доволен, так что да! Даже если кто-то действительно хочет сделать это сам, мне нравится ваш подход к подклассам, вместо того, чтобы добавлять код к каждому контроллеру. Я был шокирован, что iOS не сделала этого по умолчанию, как Android - опять же, я обнаружил, что в iOS и MacOS многого не хватает :(

Almo
23 ноября 2014 в 01:48
0

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

avatar
Muhammad Mohsin Najmuddin
25 ноября 2014 в 16:30
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];
}
Ravi Ojha
17 марта 2015 в 06:19
0

Вот что такое layoutView ??

avatar
25 октября 2014 в 11:10
32

Найдено самое простое решение

- (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];
}
MELWIN
13 ноября 2014 в 10:58
0

Экран перемещается вверх, даже если его нет внизу. т.е. если текстовое поле находится вверху, оно перемещается за пределы экрана. Как контролировать это дело?

user5228393
2 августа 2016 в 16:47
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())!

avatar
dulgan
10 октября 2014 в 07:12
5

Вот моя версия с использованием автозаполнения:

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

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

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

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

avatar
11 августа 2014 в 11:10
4

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

avatar
5 августа 2014 в 21:26
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's bottom edge might be at some offset from screen's bottom
// Calculate the exact offset
int scrollViewBottomOffset = self.view.frame.size.height - (scrollViewRect.origin.y + scrollViewRect.size.height);
int heightToBeAdjusted = keyboardRect.size.height - scrollViewBottomOffset;


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

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

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

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

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

}

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

- (IBAction)textFieldDidBeginEditing:(UITextField *)sender
{
self.activeField = sender;
}
Axort
22 января 2015 в 23:25
0

Как вернуться в исходное состояние? Я пробовал UIEdgeInsets contentInsets = UIEdgeInsetsZero; self.scrollView.contentInset = contentInsets; self.scrollView.scrollIndicatorInsets = contentInsets; как в примере, но безуспешно. Изменить: я решил это с помощью этого: [self.scrollView setContentOffset: CGPointMake (0, 0)]; это нормально?

avatar
2 июля 2014 в 20:06
8

Примечание : в этом ответе предполагается, что ваше текстовое поле находится в 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, у которого в данный момент есть клавиатура).

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

Обратите внимание, что для текстового поля мы устанавливаем его в didBeginEditing, а для 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;
}
avatar
Fonix
20 мая 2014 в 09:44
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];
}
avatar
Erik Allen
10 марта 2014 в 17:05
0

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

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

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    // A lot of the inspiration for this code came from http://coderhelper.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 в качестве ширины.

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

  • Прокрутите представление до суперпредставления: в основном я давал ограничения сверху, слева и справа.
    • 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
avatar
1 марта 2014 в 10:24
0

в (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]; 
avatar
13 января 2014 в 16:41
-2

ЕСЛИ У ВАС ЕЩЕ БОРЬБА С ЭТОМ - ПРОЧИТАЙТЕ МОЙ ПОЧТ

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

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

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

#import <UIKit/UIKit.h>

@interface KeyboardAwareController : UIViewController <UITextFieldDelegate>

@end

// // KeyboardAwareController.m // Социопатия // // Создано Admin 13.01.14. // Copyright (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

Я также сделал снимок экрана для лучшего объяснения: see the storyboard layout screenshot

Zoltán
16 июля 2014 в 07:59
2

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

avatar
PKN
27 октября 2013 в 07:26
2
  • Если текстовое поле не полностью или частично скрыто, мы не должны ничего менять.
  • Мы должны вычислить точную область пересечения (рамка клавиатуры и рамка текстового поля), которая скрыта, а затем мы должны изменить рамку представления.

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

    Объявление 3 переменных

#define PADDING 10

@interface PKViewController ()
      @property (nonatomic, assign) CGRect originalViewFrame; //original view's 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];
    }];
}
avatar
21 августа 2013 в 04:55
2

Только что нашел этот класс:

https://github.com/OliverLetterer/SLScrollViewKeyboardSupport

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

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

self.support = [[SLScrollViewKeyboardSupport alloc] initWithScrollView:self.scrollView];
avatar
user966931
14 июня 2013 в 10:51
6

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

[AutoScroller addAutoScrollTo:scrollView];

Прекрасно работать с клавиатурой в формах

quantumpotato
14 января 2013 в 05:08
0

Зарегистрируйтесь, чтобы скачать? ..Спасибо, не надо. Пожалуйста, разместите на github или подобном.

George
23 мая 2013 в 13:14
0

неплохо, но у меня проблема с этой библиотекой. Жалко, что кода нет на гитхабе. Но в любом случае спасибо.

avatar
progrmr
14 мая 2013 в 06:01
16

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

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

jaime
13 сентября 2013 в 21:57
0

Какая лицензия? Некоторые из ваших файлов имеют лицензию с открытым исходным кодом, а некоторые нет.

Almo
23 ноября 2014 в 02:05
0

Предупреждение: этот код несовместим с проектами ARC.

progrmr
23 ноября 2014 в 16:12
0

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

avatar
Jonathan Sterling
14 мая 2013 в 05:59
48

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

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

Peter Johnson
20 мая 2013 в 22:29
1

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

RJH
29 октября 2015 в 15:33
1

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

SwiftArchitect
9 февраля 2016 в 22:16
0

UITableView, к сожалению, единственный выход. Уведомления с клавиатуры хрупкие и со временем изменились. Пример кода в Stack Overflow: coderhelper.com/a/32390936/218152

Fattie
30 ноября 2017 в 20:20
0

Этот ответ на на пять лет устарел. Единственное современное решение - это что-то вроде этого ... coderhelper.com/a/41808338/294884

avatar
Mihai Damian
14 мая 2013 в 05:58
47

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

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

avatar
2 апреля 2013 в 06:47
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];
       }
 }
koen
9 октября 2013 в 17:48
0

Этот ответ был напрямую скопирован с cocoawithlove.com/2008/10/…

avatar
1 декабря 2012 в 14:53
135

Просто используя текстовые поля:

1a) Использование Interface Builder: выберите все текстовые поля => 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];
}
TheTiger
5 мая 2014 в 07:03
8

Но он также перемещает вид вверх, когда textField уже виден.

Fury
11 января 2015 в 14:24
1

Необходимо изменить CGPointMake(0, textField.frame.origin.y); на CGPointMake(0, textField.frame.origin.y + scrollView.contentInset.top);

rak appdev
3 апреля 2017 в 18:32
0

@Egor Даже после вашего комментария это не работает. Как и упомянул TheTiger, он перемещается вверх даже после того, как текстовое поле становится видимым.

tibalt
7 мая 2019 в 16:57
0

Изменение для XCode 10: «Выбрать все текстовые поля => Редактор => Вставить в => Просмотр с прокруткой»

avatar
12 октября 2012 в 23:47
2

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

- (void)textFieldDidBeginEditing:(UITextField *)sender
{
    UIScrollView *scrollView = (UIScrollView *)self.view; // assuming this method is pasted into the UIScrollView's 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];
}
avatar
12 октября 2012 в 09:14
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)

Bala
8 октября 2014 в 11:16
0

Привет, Хотджард, я получаю EXE_BAD_ACCESS в [self.view addSubview: natView];

avatar
Dheeraj V.S.
4 октября 2012 в 02:57
12

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

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

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

Morpheus78
13 декабря 2016 в 00:50
0

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

avatar
Jose Muanis
24 августа 2012 в 10:25
23

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

Ert
20 июля 2019 в 06:51
0

Ссылка на статью мертвая.

avatar
25 июля 2012 в 08:59
1

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

Спасибо,

avatar
user1105624
20 июля 2012 в 07:40
7

Попробуйте это:

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:self.m_Sp_Contact])
    {
        [self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];          
    }
}
avatar
30 января 2012 в 17:07
5

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

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

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

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

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

Ура.

avatar
savagenoob
2 января 2012 в 20:42
10

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

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

@property (nonatomic, retain) id backgroundTapDelegate;

как видите.

Maarten Bodewes
1 января 2012 в 23:56
0

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

avatar
Steve McFarlin
28 марта 2010 в 22:17
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, и у меня не было дней, чтобы изучить механизмы внутренней компоновки.

avatar
11 февраля 2010 в 11:18
31

Небольшое исправление, которое работает для многих UITextFields

#pragma mark UIKeyboard handling

#define kMin 150

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
   if (currTextField) {
      [currTextField release];
   }
   currTextField = [sender retain];
   //move the main view, so that the keyboard does not hide it.
   if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) {
        [self setViewMovedUp:YES]; 
   }
}



//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
   [UIView beginAnimations:nil context:NULL];
   [UIView setAnimationDuration:0.3]; // if you want to slide up the view

   CGRect rect = self.view.frame;
   if (movedUp)
   {
      // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
      // 2. increase the size of the view so that the area behind the keyboard is covered up.
      rect.origin.y = kMin - currTextField.frame.origin.y ;
   }
   else
   {
      // revert back to the normal state.
      rect.origin.y = 0;
   }
   self.view.frame = rect;

   [UIView commitAnimations];
}


- (void)keyboardWillShow:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately

   if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin)
   {
      [self setViewMovedUp:YES];
   }
   else if (![currTextField isFirstResponder] && currTextField.frame.origin.y  + self.view.frame.origin.y < kMin)
   {
      [self setViewMovedUp:NO];
   }
}

- (void)keyboardWillHide:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
   if (self.view.frame.origin.y < 0 ) {
      [self setViewMovedUp:NO];
   }

}


- (void)viewWillAppear:(BOOL)animated
{
   // register for keyboard notifications
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) 
                                                name:UIKeyboardWillShowNotification object:self.view.window]; 
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) 
                                                name:UIKeyboardWillHideNotification object:self.view.window]; 
}

- (void)viewWillDisappear:(BOOL)animated
{
   // unregister for keyboard notifications while not visible.
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 
}
u.gen
17 июня 2012 в 11:09
0

rect.origin.y=+currTextField.frame.origin.y работает нормально спасибо

avatar
5 февраля 2010 в 18:27
30

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

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

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