Переместить вид с клавиатуры с помощью Swift

278

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

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

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

Любая помощь будет принята с благодарностью.

Алекс Кетчпол
источник
Лучший способ сделать это - поместить свой контент в UIScrollView , а затем настроить свойство contentInset представления прокрутки по высоте клавиатуры, когда оно отображается. Абсолютно не принимайте высоту клавиатуры - используйте значение из уведомления «клавиатура покажет».
nielsbot
1
На самом деле, документы Apple рассказывают вам, как это сделать, в разделе «Управление клавиатурой»: developer.apple.com/library/ios/documentation/StringsTextFonts/…
nielsbot
11
Я думаю, что все ответы ниже не учитывают один случай: что если у вас есть несколько текстовых полей, и некоторые из них расположены в верхней части экрана? Каждый раз, когда пользователь нажимает на это текстовое поле, оно выходит за пределы экрана, и я уверен, что правильный ответ должен определить, чтоit is actually needed to scroll view up when keyboard appears
2008 г., пост.
Этот ответ может определить, действительно ли необходимо прокручивать представление вверх, когда появляется клавиатура, проверив, занимает ли редактируемое текстовое поле то же пространство, что и клавиатура: stackoverflow.com/a/28813720/6749410
HirdayGupta

Ответы:

710

Вот решение без обработки переключения с одного textField на другое:

 override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)            
    }   

func keyboardWillShow(notification: NSNotification) {            
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }            
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}

Чтобы решить эту проблему, замените две функции keyboardWillShow/Hideэтими:

func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

func keyboardWillHide(notification: NSNotification) {
    if view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

РЕДАКТИРОВАТЬ ДЛЯ SWIFT 3.0:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

РЕДАКТИРОВАТЬ ДЛЯ SWIFT 4.0:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

РЕДАКТИРОВАТЬ ДЛЯ SWIFT 4.2:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}
Борис
источник
56
Если пользователь прикасается к другому текстовому полю во время присутствия клавиатуры, представление будет перемещаться дальше вверх, что приводит к появлению черной области (размер клавиатуры) - мы должны исправить это, имея переменную, которая отслеживает, присутствует ли клавиатура или нет , например, если keyboardPresent == true, то не перемещайте источник представления и т. д. и т. д.
jonprasetyo
3
@Matthew Lin использует логическое значение, поэтому функции клавиатурыWillShow and hide работают только один раз
iluvatar_GR
11
Только одно предложение, чтобы вам не пришлось много отлаживать, как я. Если у вас есть несколько uitextfields на одном экране, размер клавиатуры может отличаться (он не показывает предложения для некоторых входов, основанных на ваших настройках), поэтому рекомендуется устанавливать self.view.frame.origin.y = 0, каждый раз ты распускаешь клавиатуру Например, он будет отображать предложения для вашего текстового поля электронной почты, поэтому размер клавиатуры будет увеличиваться, и не будут отображаться подсказки для поля пароля, поэтому размер клавиатуры будет уменьшаться.
Вандан Патель
36
Вы должны использовать, UIKeyboardFrameEndUserInfoKeyа не UIKeyboardFrameBeginUserInfoKeyпри получении размера клавиатуры. Я не уверен, почему на данный момент, но первый даст более последовательные результаты.
jshapy8
3
Пожалуйста, замените UIKeyboardFrameBeginUserInfoKeyна UIKeyboardFrameEndUserInfoKey. Первый дает начальный кадр клавиатуры, который иногда равен нулю, а второй дает конечный кадр клавиатуры.
Арнаб
90

Самый простой способ, который даже не требует никакого кода:

  1. Загрузите KeyboardLayoutConstraint.swift и добавьте (перетащите) файл в свой проект, если вы еще не используете среду анимации Spring.
  2. В раскадровке создайте нижнее ограничение для представления или текстового поля, выберите ограничение (дважды щелкните его) и в инспекторе удостоверений измените его класс с NSLayoutConstraint на KeyboardLayoutConstraint.
  3. Готово!

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

gammachill
источник
4
Чтобы выбрать нижнее ограничение, вы также можете перейти в инспектор размера, а затем дважды щелкнуть ограничение в списке - raywenderlich.com/wp-content/uploads/2015/09/…
gammachill
3
Это сработало идеально для меня. это буквально двухэтапный процесс. 1. Добавьте KeyboardLayoutConstraint.swift, 2. В раскадровке создайте нижнее ограничение для представления или текстового поля. ПРИМЕЧАНИЕ. Я удалил свои ограничения и добавил только 1 ограничение в конец представления или текстового поля и изменил его класс с NSLayoutConstraint на KeyboardLayoutConstraint. Затем любые представления / текстовые поля и т. Д. Выше я просто связал ограничения из этого элемента с элементом с помощью одного KeyboardLayoutConstraint, и в результате все видимые элементы были перемещены ВВЕРХ / ВНИЗ, когда клавиатура появляется / исчезает
Брайан
4
Это лучшее решение, так как предоставленный код не жестко кодирует какие-либо значения, такие как длина или кривая анимации или размер клавиатуры. Это также легко понять.
miguelSantirso
3
Это работает для меня, но я получаю дополнительные 50px пространства между верхней частью клавиатуры и нижней частью моего scrollView. Мне интересно, связано ли это с нижним ограничением безопасной зоны, которое я использую. Кто-нибудь сталкивался с этим?
Клифтон Лабрум
1
Это был потрясающий ответ. Очень классный дизайн. Одно предложение: если ваши текстовые представления / текстовые поля находятся в ячейках табличного представления, вы можете заметить, что представления, имеющие это ограничение, будут неловко прыгать каждый раз, когда пользователь нажимает ввод и переходит к следующему текстовому полю. Вы можете обернуть анимацию, DispatchQueue.main.async {}чтобы исправить это. Хорошая работа! Недурно!
ScottyBlades
68

Один из популярных ответов в этой теме использует следующий код:

func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}

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

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

Решение

Важно отметить, что мы передаем self.view.window в качестве нашего параметра объекта. Это предоставит нам данные с нашей клавиатуры, такие как ее высота!

@IBOutlet weak var messageField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

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

func keyboardWillHide(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    self.view.frame.origin.y += keyboardSize.height
}

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

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y -= keyboardSize.height
        })
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
}

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

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

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}

Обновление на основе вопроса из комментариев:

Если у вас есть два или более текстовых поля, вы можете проверить, равен ли ваш view.frame.origin.y нулю.

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!

    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        if self.view.frame.origin.y == 0 {
            UIView.animateWithDuration(0.1, animations: { () -> Void in
                self.view.frame.origin.y -= keyboardSize.height
            })
        }
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
     print(self.view.frame.origin.y)
}
Дэн Болье
источник
1
при работе с несколькими текстовыми полями вид продолжает двигаться вверх и не возвращается назад
Мугунтан Балакришнан
Вам придется изменить свои условия для учета текстовых полей
Дэн Болье
спасибо за ответ, я нашел ответ, который искал в этой теме, о переполнении стека stackoverflow.com/questions/1126726/…
Mugunthan Balakrishnan
@MugunthanBalakrishnan, спасибо, что подняли этот вопрос, я добавил решение.
Дэн Болье
Привет, ребята, есть ошибка. Наблюдатели не удаляются из вида после вызова в viewWillDisappear. Замените эту строку «NSNotificationCenter.defaultCenter (). RemoveObserver (self, name: UIKeyboardWillHideNotification, object: self.view.window)» на «NSNotificationCenter.defaultCenter (). RemoveObserver (self, имя: UIKeyboardWillHideNotification, затем объект: наблюдение ноль) удален
rudald
29

Добавьте это к вашему viewcontroller. Работает как шарм. Просто настройте значения.

override func viewDidLoad() {
    super.viewDidLoad()        
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil);
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil);
}

@objc func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
@objc func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}
user3677173
источник
Это работает для меня. Однако это немного вяло. Как я могу заставить это двигаться вверх гладко? Также есть способ применить его только к одному из текстовых полей, поскольку в настоящее время он делает это для всех. :(
DannieCoderBoi
2
Он может не работать с «Auto-Layout», поэтому подумайте о том, чтобы отключить его, если так.
Теодор Чурару
1
Это вызывает странное поведение с autolayout @Josh, вы ошибаетесь
Майк
5
Не делай этого! Вы не можете предполагать, что клавиатура имеет определенный размер.
nielsbot
2
Должен использовать keyboardSize. Что происходит, когда у вас есть дополнительные виды и разные высоты клавиатуры на устройствах? Отдельная клавиатура?
xtrinch
25

Я немного улучшил один из ответов, чтобы он работал с разными клавиатурами и различными текстовыми представлениями / полями на одной странице:

Добавить наблюдателей:

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

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

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

func keyboardWillHide() {
    self.view.frame.origin.y = 0
}

func keyboardWillChange(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if YOURTEXTVIEW.isFirstResponder {
            self.view.frame.origin.y = -keyboardSize.height
        }
    }
}

Удалить наблюдателей:

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

    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
scipianne
источник
3
это решение работает лучше, чем принятый ответ. Принятый ответ показывает клавиатуру только один раз, что для меня является ошибкой :)
Masih
Это работает для Xcode 10.1 и iOS 12. Принятый ответ больше не действителен.
Зеешан
Это отличный ответ, единственное, что я хотел бы добавить, - это отслеживать нижнюю безопасную область на новых устройствах (X, XS и т. Д.), Чтобы она учитывала это.
Муниб
@Munib See stackoverflow.com/a/54993623/1485230 Другие вопросы включают в себя вид не оживляющих и изменение высоты клавиатуры не следует.
Antzi
Что делать, если мой textField является верхней частью представления ..? Я имею в виду, если есть текстовое поле с происхождением Y = 0 .. ?? тогда textField идет вверх, и я не могу видеть его
Сайфан Надаф
20

Не реклама или продвижение или спам , просто хорошее решение. Я знаю, что на этот вопрос есть почти 30 ответов, и я настолько потрясен, что никто даже не упомянул об этом прекрасном проекте GitHub, который делает все это для вас и даже лучше. Все ответы просто перемещают взгляд вверх. Я только что решил все свои проблемы с этим IQKeyboardManager. У него 13000+ звезд.
Просто добавьте это в ваш подфайл, если вы используете swift

pod 'IQKeyboardManagerSwift'

а затем внутри вашего AppDelegate.swift сделать import IQKeyboardManagerSwift

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

      IQKeyboardManager.shared.enable = true // just add this line

      return true
    }
}

Добавьте строку, IQKeyboardManager.shared.enable = trueчтобы включить его.
Это решение обязательно, если вы собираетесь в производство.

WeeGee
источник
Это действительно хорошо, но последняя версия не работает для меня, я использовал 6.2.1 и импортирую как import IQKeyboardManagerи использовал IQKeyboardManager.shared().isEnabled = trueв AppDelegate
Dhanu K
2
И это работает потрясающе при использовании нескольких редактируемых текстов, Это сэкономило мое время
Dhanu K
1
Не могу поблагодарить за указание на эту замечательную библиотеку. Эта библиотека, наконец, является окончательным ответом на все глупости, связанные с клавиатурой, для которых Apple никогда не предоставляла решения. Теперь я буду использовать его для всех своих проектов, новых и старых, и сэкономить время и головную боль, которая возникает, исчезает или не исчезает эта клавиатура, или как ее скрывать, и почему она перекрывается, проблемы вызывали меня с тех пор, как день я программирую для айфонов.
Зеешан
1
Я написал свой собственный код для перемещения текстового поля, как и другие решения здесь. Я обнаружил, что IQKeyboardManager очень хорош, и теперь я буду его включать. Будет держать мой код под рукой на случай, если фреймворк не будет обновляться.
ТМ Линч
1
Этот ответ должен быть выше, намного выше.
JC
15

Для ошибки черного экрана (Swift 4 и 4.2) .

Я исправил проблему с черным экраном. В проверенном решении Высота клавиатуры изменяется после нажатия, и это вызывает черный экран.

Должен использовать UIKeyboardFrameEndUserInfoKey вместо UIKeyboardFrameBeginUserInfoKey

var isKeyboardAppear = false

override func viewDidLoad() {
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y == 0{
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
        isKeyboardAppear = true
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y != 0{
                self.view.frame.origin.y += keyboardSize.height
            }
        }
         isKeyboardAppear = false
    }
}
Али Ихсан УРАЛ
источник
Не будет работать, если есть панель вкладок. Вы должны рассчитать высоту панели вкладок, иначе между клавиатурой и видом будет черный экран.
Анкур Лахири
Это не исправляет черную область, где была клавиатура на iPhone X и новее. И каждый раз, когда клавиатура появляется и исчезает, основной вид продолжает скользить вниз.
Эдисон
14

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

В этом примере я использую нижнее ограничение из текстового поля в Bottom Layout View с начальным значением 175.

@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()        
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}

func keyboardWillShow(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 260
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

func keyboardWillHide(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 175
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}
Амро Шафи
источник
Привет, сэр, не могли бы вы сказать мне, почему это не работает, если поместить в представление, которое также содержит TableView? Он отлично работает в том же сценарии, когда он содержит CollectionView.
elarcoiris
9

В том, как мы определяем KeyboardWillHideNotification, произошли некоторые изменения.

Это решение работает с Swift 4.2 :

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


@objc func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

@objc func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y += keyboardSize.height
    }
}
Иван Ле Хьелмеланд
источник
2
Что делать, если мой textField является верхней частью представления ..? Я имею в виду, если есть текстовое поле с происхождением Y = 0 .. ?? тогда textField идет вверх, и я не могу видеть это
Сайфан Надаф
7

Swift 5.0:

После 4-5 часов борьбы я пришел с простым расширением UIViewController с простым кодом, который работает как шарм

* Вид не должен двигаться, когда TextField находится над клавиатурой

* Нет необходимости устанавливать постоянное значение NSLayoutConstraint

* Не требуется сторонняя библиотека

* Не требуется анимационный код

* Работает и над таблицей

* Это работает на автоматическом макете / автоматическое изменение размера

extension UIViewController {
    func addKeyboardObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardNotifications(notification:)),
                                               name: UIResponder.keyboardWillChangeFrameNotification,
                                               object: nil)
    }

    func removeKeyboardObserver(){
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }

    // This method will notify when keyboard appears/ dissapears
    @objc func keyboardNotifications(notification: NSNotification) {

        var txtFieldY : CGFloat = 0.0  //Using this we will calculate the selected textFields Y Position
        let spaceBetweenTxtFieldAndKeyboard : CGFloat = 5.0 //Specify the space between textfield and keyboard


        var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        if let activeTextField = UIResponder.currentFirst() as? UITextField ?? UIResponder.currentFirst() as? UITextView {
            // Here we will get accurate frame of textField which is selected if there are multiple textfields
            frame = self.view.convert(activeTextField.frame, from:activeTextField.superview)
            txtFieldY = frame.origin.y + frame.size.height
        }

        if let userInfo = notification.userInfo {
            // here we will get frame of keyBoard (i.e. x, y, width, height)
            let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let keyBoardFrameY = keyBoardFrame!.origin.y
            let keyBoardFrameHeight = keyBoardFrame!.size.height

            var viewOriginY: CGFloat = 0.0
            //Check keyboards Y position and according to that move view up and down
            if keyBoardFrameY >= UIScreen.main.bounds.size.height {
                viewOriginY = 0.0
            } else {
                // if textfields y is greater than keyboards y then only move View to up
                if txtFieldY >= keyBoardFrameY {

                    viewOriginY = (txtFieldY - keyBoardFrameY) + spaceBetweenTxtFieldAndKeyboard

                    //This condition is just to check viewOriginY should not be greator than keyboard height
                    // if its more than keyboard height then there will be black space on the top of keyboard.
                    if viewOriginY > keyBoardFrameHeight { viewOriginY = keyBoardFrameHeight }
                }
            }

            //set the Y position of view
            self.view.frame.origin.y = -viewOriginY
        }
    }
}

Добавьте это расширение UIResponder, чтобы узнать, какой TextField выбран

extension UIResponder {

    static weak var responder: UIResponder?

    static func currentFirst() -> UIResponder? {
        responder = nil
        UIApplication.shared.sendAction(#selector(trap), to: nil, from: nil, for: nil)
        return responder
    }

    @objc private func trap() {
        UIResponder.responder = self
    }
}

Тогда используйте это в любом вашем ViewController

   override func viewWillAppear(_ animated: Bool) {
        self.addKeyboardObserver()
    }

    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardObserver()
    }

  • Зарегистрировать это уведомление в func viewWillAppear(_ animated: Bool)

  • Отменить регистрацию этого уведомления в func viewWillDisappear(_ animated:Bool)

    Скачать демо здесь

Сайфан Надаф
источник
Это выглядело как лучшее решение, однако есть несколько ошибок. 1, текстовое поле перемещается вверх, но когда я начинаю набирать его, оно немного больше подпрыгивает. 2, в альбомной ориентации при наборе textField иногда прыгает влево.
Даррен
@ Darren Я пытаюсь выяснить эти ошибки, но я не нашел, не могли бы вы сказать, где вы получили эти ошибки, я имею в виду для какой версии / устройства ... ??
Сайфан Надаф
6

Для Swift 3 я сделал подкласс UIViewController, так как мне нужно было постоянное поведение во всех контроллерах представления.

class SomeClassVC: UIViewController {

  //MARK: - Lifecycle
  override func viewDidLoad() {
    super.viewDidLoad()

    addKeyboardObservers()
  }

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

    removeKeyboardObservers()
  }

  //MARK: - Overrides
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
  }

  //MARK: - Help
  func addKeyboardObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
  }

  func removeKeyboardObservers() {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
  }

  func keyboardWillShow(notification: NSNotification) {
    let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.height
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = -1 * keyboardHeight!
      self.view.layoutIfNeeded()
    })
  }

  func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = 0
      self.view.layoutIfNeeded()
    })
  }

  func resignTextFieldFirstResponders() {
    for textField in self.view.subviews where textField is UITextField {
      textField.resignFirstResponder()
    }
  }

  func resignAllFirstResponders() {
      view.endEditing(true)
  }
}
Павле Миятович
источник
Вдохновленный решением Павла, я обновил его, чтобы автоматически поднимать клавиатуру на определенный процент от оставшегося свободного места, а также рекурсивно находил сфокусированное поле для правильного расположения. Возьмите это здесь: gist.github.com/noordawod/24d32b2ce8363627ea73d7e5991009a0
Нур Давод,
Моя панель вкладок также движется вверх вместе с окном! :(
Альфи
6

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

Идея заключается в следующем:

  • чтобы получить фокус TextField абсолютную позицию Y
  • чтобы получить высоту клавиатуры
  • чтобы получить высоту экрана
  • Затем вычислите расстояние между положением клавиатуры и текстовым полем (если <0 -> сдвинуть вид вверх)
  • использовать UIView.transform вместо UIView.frame.origin.y - = .., потому что легче вернуться к исходной позиции с UIView.transform = .identity

тогда мы сможем перемещать вид только в случае необходимости и определенного смещения в oder, чтобы сфокусированное поле texField над клавиатурой

Вот код:

Swift 4

class ViewController: UIViewController, UITextFieldDelegate {

var textFieldRealYPosition: CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

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

  // Delegate all textfields

}


@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        let distanceBetweenTextfielAndKeyboard = self.view.frame.height - textFieldRealYPosition - keyboardSize.height
        if distanceBetweenTextfielAndKeyboard < 0 {
            UIView.animate(withDuration: 0.4) {
                self.view.transform = CGAffineTransform(translationX: 0.0, y: distanceBetweenTextfielAndKeyboard)
            }
        }
    }
}


@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.4) {
        self.view.transform = .identity
    }
}


func textFieldDidBeginEditing(_ textField: UITextField) {
  textFieldRealYPosition = textField.frame.origin.y + textField.frame.height
  //take in account all superviews from textfield and potential contentOffset if you are using tableview to calculate the real position
}

}

Квентин Н
источник
Очень хорошо! (В viewDidLoad вместо «ViewController» вместо «ViewController» у вас есть «GTuleViewController»).
Рен
Гораздо более полный и полезный ответ. Спасибо! Я полагаю, что проверка клавиатуры вызывается следующим образом, потому что она даст согласованный размер клавиатуры ........., если let keyboardSize = (messages.userInfo? [UIResponder.keyboardFrameEndUserInfoKey] as? NSValue) ?. cgRectValue .size
Бен
4

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

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.setTranslatesAutoresizingMaskIntoConstraints(true)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height - keyboardSize.height)
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height + keyboardSize.height)
    }
}
Грант Парк
источник
4

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

Как говорит Apple, не смешивайте эти 3 типа логики. Если у вас есть ограничения в раскадровке, не пытайтесь изменить х / у. Это определенно не работает.

ingconti
источник
4

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

Хорошая клавиатура для iOS должна:

  • Изменение размера автоматически при изменении размеров клавиатуры (ДА, ЭТО МОЖЕТ)
  • Анимировать на той же скорости, что и клавиатура
  • Анимировать, используя ту же кривую, что и клавиатура
  • Уважайте безопасные районы, если это уместно.
  • Работает и на iPad / в разобранном виде

Мой код использует NSLayoutConstraintобъявленный как@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

Вы также можете использовать преобразования, просматривать смещения, .... Я думаю, что это проще с ограничением tho. Он работает, устанавливая ограничение снизу, вам может потребоваться изменить код, если ваша константа не равна 0 / Не снизу.

Вот код:

// In ViewDidLoad
    NotificationCenter.default.addObserver(self, selector: #selector(?MyViewController.keyboardDidChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)


@objc func keyboardDidChange(notification: Notification) {
    let userInfo = notification.userInfo! as [AnyHashable: Any]
    let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
    let animationCurve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber
    bottomLayoutConstraint.constant = view.frame.height - endFrame.origin.y - view.safeAreaInsets.bottom // If your constraint is not defined as a safeArea constraint you might want to skip the last part.
    // Prevents iPad undocked keyboard.
    guard endFrame.height != 0, view.frame.height == endFrame.height + endFrame.origin.y else {
        bottomLayoutConstraint.constant = 0
        return
    }
    UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: animationCurve.intValue)!)
    UIView.animate(withDuration: animationDuration.doubleValue) {
        self.view.layoutIfNeeded()
        // Do additional tasks such as scrolling in a UICollectionView
    }
}
Antzi
источник
3

его 100% идеальный ответ для всех парней обновления высоты стола при открытой клавиатуре

Для Swift4.2

   override func viewDidLoad() {
      super.viewDidLoad()
      NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)

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

   @objc func keyboardWillShow(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {

        var userInfo = notification.userInfo!
        var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        keyboardFrame = self.view.convert(keyboardFrame, from: nil)

        var contentInset:UIEdgeInsets = self.tbl.contentInset
          contentInset.bottom = keyboardFrame.size.height
          self.tbl.contentInset = contentInset
    }
}

   @objc func keyboardWillHide(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.tbl.contentInset = contentInset
    }
}

Swift3.2

    override func viewDidLoad() {
          super.viewDidLoad()

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    func keyboardWillShow(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         //self.view.frame.origin.y -= keyboardSize.height
         var userInfo = notification.userInfo!
         var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
          keyboardFrame = self.view.convert(keyboardFrame, from: nil)

          var contentInset:UIEdgeInsets = self.tbl.contentInset
          contentInset.bottom = keyboardFrame.size.height
          self.tbl.contentInset = contentInset

       }
    }

    func keyboardWillHide(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
         self.tbl.contentInset = contentInset
         }
    }
Маулик Патель
источник
Это лучший ответ. tbl должен быть tableView, и я добавил некоторые отступы: contentInset.bottom = keyboardFrame.size.height + 10
iphaaw
2

Для Swift 3

func textFieldDidBeginEditing(_ textField: UITextField) { // became first responder

    //move textfields up
    let myScreenRect: CGRect = UIScreen.main.bounds
    let keyboardHeight : CGFloat = 216

    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var needToMove: CGFloat = 0

    var frame : CGRect = self.view.frame
    if (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight - 30)) {
        needToMove = (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight - 30);
    }

    frame.origin.y = -needToMove
    self.view.frame = frame
    UIView.commitAnimations()
}

func textFieldDidEndEditing(_ textField: UITextField) {
    //move textfields back down
    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var frame : CGRect = self.view.frame
    frame.origin.y = 0
    self.view.frame = frame
    UIView.commitAnimations()
}
Джелил Бозкурт
источник
2

Свифт 4:

У меня возникла проблема с наиболее приемлемым ответом, из-за которой скрытие клавиатуры не возвращало представление полностью вниз страницы (только частично). Это сработало для меня (+ обновлено для Swift 4).

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardWhenTappedAround()
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0{
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0{
            self.view.frame.origin.y = 0
        }
    }
}
Rbar
источник
Что делать, если мой textField является верхней частью представления ..? Я имею в виду, если есть текстовое поле с происхождением Y = 0 .. ?? тогда textField идет вверх, и я не вижу его
Сайфан Надаф
2

Аналогично ответу @Boris, но в Swift 5 :

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

@IBAction func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@IBAction func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}
Джерри Чонг
источник
1

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

class MyViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var firstTextField: UITextField!
@IBOutlet weak var secondTextField: UITextField!

var activeTextField: UITextField!
var viewWasMoved: Bool = false


override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

override func viewDidDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

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

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

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}


func keyboardWillShow(notification: NSNotification) {

    let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()

    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height

    let activeTextFieldRect: CGRect? = activeTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin

    if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
        self.viewWasMoved = true
        self.view.frame.origin.y -= keyboardSize!.height
    } else {
        self.viewWasMoved = false
    }
}

func keyboardWillHide(notification: NSNotification) {
    if (self.viewWasMoved) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}
Vah.Sah
источник
Не забудьте установить делегата на textFields
SwingerDinger
Измените условие в показе клавиатуры как, если (! CGRectContainsPoint (aRect, newOrgin!) &&! Self.viewWasMoved)
KingofBliss
добавьте self.viewWasMoved = false при сбросе фрейма
KingofBliss
1

Обновлено для Swift 3 ...

Как уже говорили другие, вам нужно добавить наблюдателей уведомлений в методе viewDidLoad () вашего контроллера, вот так:

NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, object: nil, queue: nil)
    { notification in
    self.keyboardWillShow(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, object: nil, queue: nil)
    { notification in
    self.keyboardWillHide(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidHide, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

Не забудьте удалить своих наблюдателей, где это необходимо (я делаю это в методе viewWillDisappear ())

NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: nil)

Затем реализуйте свои методы show и hide - обратите внимание на строку, которая указывает приложению игнорировать события взаимодействия (beginIgnoringInteractionEvents). Это важно, так как без него пользователь может нажать на поле или даже прокрутку и вызвать сдвиг во второй раз, что приведет к ужасному сбою пользовательского интерфейса. Игнорирование событий взаимодействия до отображения и скрытия клавиатуры предотвратит это:

func keyboardWillShow(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y -= keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top += keyboardSize.height
        }
    }

func keyboardWillHide(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y += keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top -= keyboardSize.height
        }
    }

Наконец, повторно включите взаимодействие с пользователем (помните, этот метод срабатывает после того, как клавиатура didShow или didHide):

func enableUserInteraction()
    {
    UIApplication.shared.endIgnoringInteractionEvents()
    }
Джин Лопарко
источник
1

Код Swift 3

var activeField: UITextField?

override func viewDidLoad() {
    super.viewDidLoad()

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

func textFieldDidBeginEditing(_ textField: UITextField){
    activeField = textField
}

func textFieldDidEndEditing(_ textField: UITextField){
    activeField = nil
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if (self.activeField?.frame.origin.y)! >= keyboardSize.height {
            self.view.frame.origin.y = keyboardSize.height - (self.activeField?.frame.origin.y)!
        } else {
            self.view.frame.origin.y = 0
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}
Рохит Шарма
источник
1

Если у вас есть 2 или более текстовых поля в одном и том же VC, и пользователь нажимает на одно из них, а затем на другое, не вызывая функцию keyboardWillHide, представление снова идет вверх, что не является необходимым, поскольку у вас будет клавиатура, пустое пространство с высотой клавиатуры и вид, используя код в ответе, который я отредактировал:

override func viewDidLoad() {       
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y += keyboardSize.height
    }
}

Чтобы решить эту проблему, замените две функции «KeyboardWillShow / Hide» на эти:

func keyboardWillShow(notification: NSNotification) {
 if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    if view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y != 0 {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}
Мистер Xcoder
источник
Что делать, если мой textField является верхней частью представления ..? Я имею в виду, если есть текстовое поле с происхождением Y = 0 .. ?? тогда textField идет вверх, и я не могу видеть это
Сайфан Надаф
1

Решение Бориса ОЧЕНЬ хорошее, но иногда вид может быть искажен.

Для идеального выравнивания используйте код ниже

override func viewDidLoad() {
super.viewDidLoad()            
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}

Функции:

@objc func keyboardWillShow(notification: NSNotification) {        
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
    }
}}    

И,

@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y != 0{
        self.view.frame.origin.y = 0 
    }
} }
Эрай Алпарслан
источник
0

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

https://youtu.be/VuiPGJOEBH4

Просто эти шаги:

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

-Подключите все текстовые поля и прокрутите представление как делегаты к контроллеру представления.

-Соедините все текстовые поля и прокрутите представление с IBOutlet.

class ViewController: UIViewController, UITextFieldDelegate {

-Добавить протокол UITextFieldDelegate в ваш класс

@IBOutlet var stateAddress: UITextField!
@IBOutlet var zipAddress: UITextField!
@IBOutlet var phoneNumber: UITextField!
@IBOutlet var vetEmailAddress: UITextField!    
@IBOutlet weak var scrollView: UIScrollView!

-Добавить методы UITextFieldDelegate в ваш файл swift:

func textFieldShouldReturn(textField: UITextField) -> Bool {

    textField.resignFirstResponder()
    return true
}


func textFieldDidBeginEditing(textField: UITextField) {

    if (textField == self.stateAddress) {
        scrollView.setContentOffset(CGPointMake(0, 25), animated: true)
    }
    else if (textField == self.zipAddress) {
        scrollView.setContentOffset(CGPointMake(0, 57), animated: true)
    }
    else if (textField == self.phoneNumber) {
        scrollView.setContentOffset(CGPointMake(0, 112), animated: true)
    }
    else if (textField == self.vetEmailAddress) {
        scrollView.setContentOffset(CGPointMake(0, 142), animated: true)
    }
}

func textFieldDidEndEditing(textField: UITextField) {

    scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}

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

Таким образом, я сделал свой пиксель зрения идеальным!

bme003
источник
0

Эта функция должна быть встроена в Ios, однако мы должны сделать это извне.
Вставьте приведенный ниже код
* Чтобы переместить представление, когда textField находится под клавиатурой,
* Не перемещать представление, когда textField находится над клавиатурой
* Чтобы переместить View, основываясь на высоте клавиатуры, когда это необходимо.
Это работает и проверено во всех случаях.

import UIKit

class NamVcc: UIViewController, UITextFieldDelegate
{
    @IBOutlet weak var NamTxtBoxVid: UITextField!

    var VydTxtBoxVar: UITextField!
    var ChkKeyPadDspVar: Bool = false
    var KeyPadHytVal: CGFloat!

    override func viewDidLoad()
    {
        super.viewDidLoad()

        NamTxtBoxVid.delegate = self
    }

    override func viewWillAppear(animated: Bool)
    {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadVyd(_:)),
            name:UIKeyboardWillShowNotification,
            object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadHyd(_:)),
            name:UIKeyboardWillHideNotification,
            object: nil);
    }

    func textFieldDidBeginEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = TxtBoxPsgVar
    }

    func textFieldDidEndEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = nil
    }

    func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
    {
        self.VydTxtBoxVar.resignFirstResponder()
        return true
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
    {
        view.endEditing(true)
        super.touchesBegan(touches, withEvent: event)
    }

    func TdoWenKeyPadVyd(NfnPsgVar: NSNotification)
    {
        if(!self.ChkKeyPadDspVar)
        {
            self.KeyPadHytVal = (NfnPsgVar.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height

            var NonKeyPadAraVar: CGRect = self.view.frame
            NonKeyPadAraVar.size.height -= self.KeyPadHytVal

            let VydTxtBoxCenVal: CGPoint? = VydTxtBoxVar?.frame.origin

            if (!CGRectContainsPoint(NonKeyPadAraVar, VydTxtBoxCenVal!))
            {
                self.ChkKeyPadDspVar = true
                UIView.animateWithDuration(1.0,
                    animations:
                    { self.view.frame.origin.y -= (self.KeyPadHytVal)},
                    completion: nil)
            }
            else
            {
                self.ChkKeyPadDspVar = false
            }
        }

    }

    func TdoWenKeyPadHyd(NfnPsgVar: NSNotification)
    {
        if (self.ChkKeyPadDspVar)
        {
            self.ChkKeyPadDspVar = false
            UIView.animateWithDuration(1.0,
                animations:
                { self.view.frame.origin.y += (self.KeyPadHytVal)},
                completion: nil)
        }
    }

    override func viewDidDisappear(animated: Bool)
    {
        super.viewWillDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self)
        view.endEditing(true)
        ChkKeyPadDspVar = false
    }
}

| :: | Иногда View будет вниз, в этом случае используйте высоту +/- 150:

    NonKeyPadAraVar.size.height -= self.KeyPadHytVal + 150

    { self.view.frame.origin.y -= self.KeyPadHytVal  - 150},
                    completion: nil)

    { self.view.frame.origin.y += self.KeyPadHytVal  - 150},
                completion: nil)
Суджай ООН
источник
0
func keyboardWillShow(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y = self.view.frame.height - (self.view.frame.height + keyboardSize.height)
    }

}

func keyboardWillHide(notification: NSNotification) {
        self.view.frame.origin.y = 0
}

оно должно быть более стабильным

Hadevs Play
источник
0
 override func viewWillAppear(animated: Bool)
 {
 super.viewWillAppear(animated)

 NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
 NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

 }

 // MARK: - keyboard
 func keyboardWillShow(notification: NSNotification) 
{

if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: keyboardSize.height, right:contentInsets.right)
                    // ...
                } else {
                    // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
                }
            } else {
                // no userInfo dictionary in notification
            }
        }

func keyboardWillHide(notification: NSNotification) 
{
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: 0, right:contentInsets.right)
 }
Гималийский шах
источник
0

Используйте следующий код для просмотра вверх на UITextField нажал

func textFieldDidBeginEditing(textField: UITextField) {
    ViewUpanimateMoving(true, upValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
    ViewUpanimateMoving(false, upValue: 100)
}
func ViewUpanimateMoving (up:Bool, upValue :CGFloat){
    var durationMovement:NSTimeInterval = 0.3
    var movement:CGFloat = ( up ? -upValue : upValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(durationMovement)
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}
Jugal K Balara
источник
0

Я сделал Cocoapod, чтобы упростить вопрос:

https://github.com/xtrinch/KeyboardLayoutHelper

Как это использовать:

Сделайте автоматическое расположение нижнего ограничения, присвойте ему класс KeyboardLayoutConstraint в модуле KeyboardLayoutHelper, и модуль выполнит всю работу, необходимую для его увеличения, чтобы он соответствовал появившейся и исчезающей клавиатуре. Смотрите пример проекта на примерах, как его использовать (я сделал два: textFields внутри scrollView и вертикально центрированные textFields с двумя основными представлениями - login & register).

Ограничение нижнего макета может касаться вида контейнера, самого textField и всего, что вы назовете.

xtrinch
источник