Переміщення подання за допомогою клавіатури за допомогою Swift


278

У мене є додаток із текстовим полем у нижній половині подання. Це означає, що коли я переходжу до тексту, клавіатура охоплює текстове поле.

Як би я міг рухати погляд вгору під час набору тексту, щоб я міг бачити, що я набираю, а потім переміщую його назад до початкового місця, коли клавіатура зникає?

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

Будь-яка допомога буде дуже вдячна.


Найкращий спосіб зробити це - розмістити вміст всередині UIScrollView , а потім відрегулювати властивість вмісту перегляду прокрутки на вигляд клавіатури на висоту клавіатури, коли вона відображається. Абсолютно не припускайте висоту клавіатури - використовуйте значення сповіщення "клавіатура покаже".
nielsbot

1
Насправді документи Apple розповідають, як це зробити, у розділі "Керування клавіатурою": developer.apple.com/library/ios/documentation/StringsTextFonts/…
nielsbot

11
Я думаю, що всі відповіді нижче не враховують один випадок: що робити, якщо у вас є кілька текстових полів, а деякі з них розташовані у верхній частині екрана? Щоразу, коли користувач натискає це текстове поле, воно виходить за межі екрана, я впевнений, що правильна відповідь повинна виявити, чи будеit is actually needed to scroll view up when keyboard appears
theDC

Ця відповідь може виявити чи так це насправді необхідно , щоб прокрутити вид вгору , коли клавіатура з'являється, перевіряючи , якщо текстове поле в даний час редагується займає таке ж місце , як і клавіатура: stackoverflow.com/a/28813720/6749410
HirdayGupta

Відповіді:


710

Ось рішення, не обробляючи перемикання з одного текстового поля на інше:

 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
Якщо користувач торкнеться іншого текстового поля, коли клавіатура присутня, подання буде висунуте далі, що спричинить чорну область (розмір клавіатури) - нам це потрібно виправити, маючи змінну, яка відслідковує, чи клавіатура присутня чи ні . Наприклад, якщо клавіатураPresent == true, то не пересувайте джерело перегляду тощо тощо
jonprasetyo

3
@Matthew Lin використовує булеву функцію, тому функції клавіатуриWillShow і приховування працюють лише один раз
iluvatar_GR

11
Лише одна пропозиція, так що вам не доведеться багато налагоджувати, як я. Якщо у вас є кілька полів uitextfield на одному екрані, розмір клавіатури може змінюватись (він не відображає пропозицій щодо деяких входів на основі ваших налаштувань), тому бажано встановлювати self.view.frame.origin.y = 0 щоразу ви відхиляєте клавіатуру. Наприклад, він відображатиме параметри для текстового поля вашої електронної пошти, тому розмір клавіатури збільшуватиметься, і не відображатиметься пропозицій щодо поля пароля, тому розмір клавіатури зменшиться.
Вандан Патель

36
Вам потрібно скористатися, UIKeyboardFrameEndUserInfoKeyа не UIKeyboardFrameBeginUserInfoKeyпри отриманні розміру клавіатури. Я не впевнений, чому зараз, але перший дасть більш послідовні результати.
jshapy8

3
Будь ласка, замініть UIKeyboardFrameBeginUserInfoKeyна UIKeyboardFrameEndUserInfoKey. Перший дає початковий кадр клавіатури, який іноді дорівнює нулю, а другий - кінцевий кадр клавіатури.
Арнаб

90

Найпростіший спосіб, який навіть не потребує коду:

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

Об'єкт автоматично рухається вгору за допомогою клавіатури, синхронізуючись.


4
Щоб вибрати нижнє обмеження, ви також можете перейти до розміру інспектора, а потім двічі клацнути на обмеження у списку - raywenderlich.com/wp-content/uploads/2015/09/…
gammachill

3
Це працювало ідеально для мене. це буквально двоступеневий процес. 1. Додайте KeyboardLayoutConstraint.swift, 2. У розкладі створіть нижнє обмеження для подання чи текстового поля. ПРИМІТКА. Я видалив свої обмеження та додав лише 1 обмеження до нижньої частини перегляду чи текстового поля та змінив його клас з NSLayoutConstraint на KeyboardLayoutConstraint. Тоді будь-які погляди / текстові поля тощо вище я просто з'єднав обмеження від цього елемента до пункту за допомогою однієї KeyboardLayoutConstraint. Результатом було те, що всі елементи перегляду переміщуються вгору / вниз, коли з'являється / зникає клавіатура
Brian

4
Це найкраще рішення: наданий код не жорстко кодує такі значення, як довжина чи крива анімації чи розмір клавіатури. Це також легко зрозуміти.
miguelSantirso

3
Це працює для мене, але я отримую додатковий проміжок у 50 пікселів між верхньою частиною клавіатури та нижньою частиною мого 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
працюючи з декількома текстовими полями, подання рухається вгору і не повертається вниз
Mugunthan Balakrishnan

Вам доведеться змінити умови, щоб обліковувати текстові поля
Дан Болье,

спасибо за ответ, я знайшов відповідь я шукав у цій темі на переповнення стека stackoverflow.com/questions/1126726 / ...
Mugunthan Balakrishnan

@MugunthanBalakrishnan спасибі за те, що довів це, я додав рішення.
Dan Beaulieu

Привіт, хлопці, є помилка. Спостерігачі не видаляються з виду після виклику в viewWillDisappear. Замініть цей рядок "NSNotificationCenter.defaultCenter (). RemoveObserver (self, name: UIKeyboardWillHideNotification, object: self.view.window)" на "NSNotificationCenter.defaultCenter (). RemoveObserver (self, name: UIKeyboardWillHideNotification, object: nil)" видалено
rudald

29

Додайте це до свого контролера перегляду. Працює як шарм. Просто відрегулюйте значення.

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
}

Це працює для мене. Однак це трохи похмуро. Як я можу змусити це рухатися гладко? також є спосіб застосувати його лише до одного з текстових полів, як це зараз робить це для всіх. :(
DannieCoderBoi

2
Можливо, це не працює з "Автоматичною компоновкою", тому подумайте про її деактивацію, якщо так.
Теодор Цюрару

1
Це викликає певну поведінку з autolayout @Josh, ви помиляєтесь
Майк

5
Не робіть цього! Ви не можете припустити, що клавіатура певного розміру.
nielsbot

2
Слід використовувати клавіатуру. Що відбувається, коли на пристроях ви маєте перегляд аксесуарів та різну висоту клавіатури? Окрема клавіатура?
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)
}

3
це рішення працює краще, ніж прийнята відповідь. Прийнята відповідь показує клавіатуру лише один раз, яка для мене є помилкою :)
Масіх

Це працює для Xcode 10.1 та iOS 12. Прийнята відповідь більше не дійсна.
Зеешан

Це відмінна відповідь. Єдине, що я хотів би додати, - це відслідковувати нижню безпечну зону на нових пристроях (X, XS тощо), щоб вона відповідала цьому.
Муніб

@Munib See stackoverflow.com/a/54993623/1485230 Інші питання включають в себе вигляд не оживляючих і зміна висоти клавіатури не слід.
Antzi

що робити, якщо моє textField переглядається ..? я маю на увазі, якщо є текстове поле з початком Y = 0 .. ?? то textField піднімається, і я не можу його побачити
Сайфан Надаф

18

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

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щоб увімкнути це
рішення. Це рішення є обов'язковим, якщо ви збираєтеся виробляти.


Це дійсно добре, але остання версія для мене не працює, я використовував 6.2.1 та імпортую як import IQKeyboardManagerі використовується IQKeyboardManager.shared().isEnabled = trueв AppDelegate
Dhanu K

2
І це чудово працює при використанні декількох текстів для редагування. Це врятувало мій час
Dhanu K

1
Не можу подякувати за те, що вказали на цю чудову бібліотеку. Ця бібліотека, нарешті, ЗАКЛЮЧИТЕЛЬНИЙ ВІДПОВІД для всіх дурниць, пов'язаних з клавіатурою, для яких Apple ніколи не давала рішення. Тепер я буду використовувати його для всіх своїх нових проектів, нових і старих, і заощаджую час і головний біль, які ця клавіатура з'являється, зникає чи не зникає, або як її приховати, і чому вона перекривається, проблеми викликають у мене з часу день я програмую для iPhone.
Zeeshan

1
Я написав власний код для переміщення текстового поля, як і інші рішення тут. Я виявив, що IQKeyboardManager дуже хороший, і зараз я його включатиму. Зберігатиме мій код зручним на випадок, якщо фреймворк не буде оновлений.
ТМ Лінч

@DhanuK, щойно знайшла цю бібліотеку і працює чудово, і це не легко. Код делегата програми оновлено до IQKeyboardManager.shared.enable = true
adougies

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пересуваєте подання, змінюючи його значення обмеження (наприклад, нижнє або верхнє обмеження) на заздалегідь задане значення або ви можете використовувати значення розміру клавіатури.

У цьому прикладі я використовую обмеження внизу від текстового поля до подання макета з початковим значенням 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

Швидкий 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
Noor Dawod

Моя панель вкладок також рухається вгору з вікном! :(
Альфі

6

Затверджена відповідь не враховує положення текстового поля і має певну помилку (подвійне переміщення, ніколи не повертайтеся до первинного положення, зміщення, навіть якщо текстове поле знаходиться на вершині виду ...)

Ідея така:

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

тоді ми зможемо перемістити подання лише у разі необхідності та конкретного зміщення в одері, щоб сфокусоване texField було над клавіатурою

Ось код:

Швидкий 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 у вас є "VehiculeViewController" замість просто "ViewController").
оновлення

Набагато повніша і корисна відповідь. Дякую! Я пропоную перевірку клавіатури викликати наступним чином, тому що вона дасть послідовний розмір клавіатури ......... якщо дозволити клавіатуруSize = (notification.userInfo? [UIResponder.keyboardFrameEndUserInfoKey] як? 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 типи логіки. Якщо у вас є обмеження в дошці розкадрувань, не намагайтеся змінювати х / у. Це остаточно не працює.


4

Тому жодна з інших відповідей, здається, не відповідає правильності.

Хороша поведінка клавіатури на iOS повинна:

  • Автоматично змінювати розмір, коли клавіатура змінює розміри (ТАК МОЖЕ)
  • Анімуйте з тією ж швидкістю, що і клавіатура
  • Анімація, використовуючи ту саму криву, що і клавіатура
  • Поважайте безпечні зони, якщо це доречно.
  • Працює і в режимі iPad / Unndocked

Мій код використовує NSLayoutConstraint оголошений як@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

Ви також можете використовувати перетворення, переглядати компенсації, .... Я думаю, що це простіше з обмеженням Тхо. Це працює, встановивши обмеження на низ, можливо, вам знадобиться змінити код, якщо ваша константа не дорівнює 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
    }
}

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

Швидкий3.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, і я додав трохи padding: 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
        }
    }
}

що робити, якщо моє 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
        }
    }
}

Не забудьте встановити Делегата на текстові поля
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)

Потім застосуйте свої шоу та прихойте методи - помітьте рядок, який повідомляє програмі ігнорувати події взаємодії (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

Якщо у вас є два або більше текстових полів на одному і тому ж VC, і користувач натискає на одне з них, а потім натискає на інше, не викликаючи функцію клавіатуриWillHide, подання ще один раз піднімається вгору, що не потрібно, оскільки у вас буде клавіатура, порожній простір, який має висоту клавіатури, а потім вигляд, використовуючи код у відповіді, яку я редагував:

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

що робити, якщо моє 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 методи до вашого швидкого файлу:

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). Останнє говорить, коли ви торкаєтесь клавіатури, огляд прокрутки повертається до початкового місця.

Я зробив свій піксель перегляду ідеальним таким чином!


0

Ця функція шуд побудована в Іосі, однак нам потрібно це робити зовні.
Вставте нижній код
* Щоб перемістити подання, коли textField знаходиться під клавіатурою,
* Не переміщувати подання, коли textField знаходиться над клавіатурою
* Перемістити Перегляд залежно від висоти клавіатури, коли це необхідно.
Це працює і перевірено у всіх випадках.

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
}

він повинен бути більш стійким


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

0

Я зробив кокапод, щоб спростити справу:

https://github.com/xtrinch/KeyboardLayoutHelper

Як ним користуватися:

Зробіть нижнє обмеження для автоматичної компонування, надайте йому клас KeyboardLayoutConstraint в модулі KeyboardLayoutHelper і стручок зробить необхідну роботу, щоб збільшити його для розміщення з'являються і зникаючих клавіатури. Дивіться приклад проекту на прикладах його використання (я зробив два: textFields всередині scrollView і вертикально центровані текстові поля з двома основними видами - вхід та реєстрація).

Нижнє обмеження макета може містити вигляд контейнера, саме textField, будь-що, що ви називаєте.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.