Перемістіть текстове поле, коли клавіатура відображається швидко


217

Я використовую Swift для програмування в iOS, і я використовую цей код для переміщення UITextField, але він не працює. Я keyboardWillShowправильно називаю функцію , але текстове поле не рухається. Я використовую автоматичний розклад.

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

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self);
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        //let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)

        var frame = self.ChatField.frame
        frame.origin.y = frame.origin.y - keyboardSize.height + 167
        self.chatField.frame = frame
        println("asdasd")
    }
}

2
Посібник із посібниками із файлами проекту: codebeaulieu.com/43/…
Dan Beaulieu

Можливо, deinit та viewDidLoad не врівноважені.
Рікардо

На основі документів Apple і особистого досвіду. Ось мій git repo за допомогою UIScrollView для переміщення TF: github.com/29satnam/MoveTextFieldWhenKeyboardAppearsSwift
Codetard

Відповіді:


315

Є кілька вдосконалень, які слід зробити в існуючих відповідях.

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

По-друге, параметри анімації можна витягнути з повідомлення, щоб забезпечити належне поєднання анімації.

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

Швидкий 3

class MyViewController: UIViewController {

// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()
    // Note that SO highlighting makes the new selector syntax (#selector()) look
    // like a comment but it isn't one
    NotificationCenter.default.addObserver(self,
        selector: #selector(self.keyboardNotification(notification:)),
        name: NSNotification.Name.UIKeyboardWillChangeFrame,
        object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame.origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
        if endFrameY >= UIScreen.main.bounds.size.height {
            self.keyboardHeightLayoutConstraint?.constant = 0.0
        } else {
            self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
        }
        UIView.animate(withDuration: duration,
                                   delay: TimeInterval(0),
                                   options: animationCurve,
                                   animations: { self.view.layoutIfNeeded() },
                                   completion: nil)
    }
}

(Відредаговано для того, щоб обліковувати клавіатуру, яка анімувала екран, а не зменшуватись, згідно з дивовижним коментарем @ Gabox нижче)

Швидкий 5

class MyViewController: UIViewController {

// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()
    // Note that SO highlighting makes the new selector syntax (#selector()) look
    // like a comment but it isn't one
    NotificationCenter.default.addObserver(self,
        selector: #selector(self.keyboardNotification(notification:)),
        name: UIResponder.keyboardWillChangeFrameNotification,
        object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame?.origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
        if endFrameY >= UIScreen.main.bounds.size.height {
            self.keyboardHeightLayoutConstraint?.constant = 0.0
        } else {
            self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
        }
        UIView.animate(withDuration: duration,
                                   delay: TimeInterval(0),
                                   options: animationCurve,
                                   animations: { self.view.layoutIfNeeded() },
                                   completion: nil)
    }
}

1
@JosephLord приємно. але я виявив, що це не працює, коли клавіатура ховається, оскільки endFrame?.size.heightне є нульовою. Я отримав кінцевий кадр як UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 1024}, {768, 264}}";. Побіг на iOS 8.3 iPad Simulator, Portrait. Xcode6.3 beta4.
Хлунг

8
якщо клавіатура не ховається, спробуйте скористатися цим кодом, якщо endFrame? .origin.y> = UIScreen.mainScreen (). bounds.size.height {self.keyboardHeightLayoutConstraint? .constant = 0.0} else {self.keyboardHeightLayoutConstraint? .constant = endFrame.size.height}
Габріель

3
keyBoardHeightLayoutConstraint - це обмеження, визначене в InterfaceBuilder, що обмежує нижню частину подання, яку ви хочете перемістити / зменшити до нижньої інструкції щодо макета або до нижньої частини головного виду контролера перегляду. Константа спочатку встановлюється на нуль і буде налаштована, щоб звільнити місце для клавіатури, коли клавіатура з'явиться або змінить розмір.
Йосип Лорд

2
Зауважте, що .UIKeyboardWillChangeFrameпідключена апаратна клавіатура не спрацьовує, навіть якщо клавіатура iOS зникає. Вам потрібно також спостерігати .UIKeyboardWillHide, щоб зловити цей край.
jamesk

1
@Sulthan працює нормально. Моє питання полягає в тому, що стає трохи вище, ніж на клавіатурі. чи можна це виправити?
Павлос

128

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

func keyboardWasShown(notification: NSNotification) {
    let info = notification.userInfo!
    let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()

    UIView.animateWithDuration(0.1, animations: { () -> Void in
        self.bottomConstraint.constant = keyboardFrame.size.height + 20
    })
}

Жорстке кодування 20 додається лише для того, щоб трохи попнути текстове поле над клавіатурою. Інакше верхній край клавіатури та нижнє поле текстового поля будуть торкатися.

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


1
Чи можете ви пояснити мені pls, як я це визначу? Дякую! Я завжди контролюю все на раскадровці
Педро Манфреди

4
bottomConstraint - це ім'я, яке я дав обмеженню. Я вибрав обмеження, перетягнув і створив до нього IBOutlet і дав це ім'я. Ви можете створювати IBOutlets з обмеженнями так само, як це можна зробити з іншими елементами інтерфейсу, такими як кнопки та текстові поля.
Ісуру

2
Ця відповідь спрацювала чудово, за винятком того, що анімація трапилася для мене одразу. Перевірте, як я анімувати зміни обмежень? як правильно анімувати.
Адам Джонс

2
@ vinbhai4u Ви повинні зареєструватися для UIKeyboardWillShowNotificationповідомлення. Подивіться на код у питанні щодо ОП.
Ісуру

8
@AdamJohns Щоб анімувати зміну обмеження, оновіть константу за межами animateWithDurationта дзвоніть self.view.layoutIfNeeded()всередині анімаційного блоку.
Макс

110

Просте рішення - перемістити погляд вгору з постійною висотою клавіатури.

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

@objc func keyboardWillShow(sender: NSNotification) {
     self.view.frame.origin.y = -150 // Move view 150 points upward 
}

@objc func keyboardWillHide(sender: NSNotification) {
     self.view.frame.origin.y = 0 // Move view to original position  
}

Швидкий 5:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(sender:)), name: UIResponder.keyboardWillShowNotification, object: nil);

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

4
Мені подобається це просте рішення. Але я додав клавіатуруПоказ булевого, оскільки я перемістив не одне текстове поле. Я кладу клавіатуру лише один раз, поки вона відображається. Дякую.
Кен

2
замість того, щоб переглядати перегляд, перемістіть textView
ericgu

1
Це збереже мінус значення перегляду, якщо користувач переключить мову введення.
Джеффрі Нео

замість зміни self.view я зробив self.myConstraint значення, воно працює, але справа в тому, що погляд (до якого застосовується обмеження) продовжує рухатися вгору. хтось стикався з цим питанням?
Саші

5
Замість self.view.frame.origin.y -= 150використання self.view.frame.origin.y = -150і замість self.view.frame.origin.y += 150використання self.view.frame.origin.y = 0. Це запобігає переміщенню огляду на 150 при кожному дотику до нового поля.
gunwin

43

Щоб перемістити свій погляд під час редагування текстового поля, спробуйте це, я застосував це,

Варіант 1: - ** ** Оновлення в Swift 5.0 та iPhone X, XR, XS та XS Max Move за допомогою NotificationCenter

  • Зареєструйте це повідомлення в func viewWillAppear(_ animated: Bool)

  • Скасуйте це Повідомлення в func viewWillDisappear(_ animated: Bool)

Примітка: - Якщо ви не скасуєте реєстрацію, ніж це буде дзвонити з дочірнього класу, і це стане причиною збоїв або ще.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillShow(notification:)), name:  UIResponder.keyboardWillShowNotification, object: nil )
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}

@objc func keyboardWillShow( notification: Notification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
        var newHeight: CGFloat
        let duration:TimeInterval = (notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
        if #available(iOS 11.0, *) {
            newHeight = keyboardFrame.cgRectValue.height - self.view.safeAreaInsets.bottom
        } else {
            newHeight = keyboardFrame.cgRectValue.height
        }
        let keyboardHeight = newHeight  + 10 // **10 is bottom margin of View**  and **this newHeight will be keyboard height**
        UIView.animate(withDuration: duration,
                       delay: TimeInterval(0),
                       options: animationCurve,
                       animations: {
                        self.view.textViewBottomConstraint.constant = keyboardHeight **//Here you can manage your view constraints for animated show**
                        self.view.layoutIfNeeded() },
                       completion: nil)
    }
}

Варіант 2: - Його робота прекрасна

func textFieldDidBeginEditing(textField: UITextField) {
        self.animateViewMoving(up: true, moveValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
        self.animateViewMoving(up: false, moveValue: 100)
}

func animateViewMoving (up:Bool, moveValue :CGFloat){
    var movementDuration:NSTimeInterval = 0.3
    var movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

Я отримав цю відповідь від цього джерела , коли UITextField рухається вгору, коли клавіша з'являється в Swift

IN Swift 4 ---

func textFieldDidBeginEditing(_ textField: UITextField) {
        animateViewMoving(up: true, moveValue: 100)
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        animateViewMoving(up: false, moveValue: 100)
    }
    func animateViewMoving (up:Bool, moveValue :CGFloat){
        let movementDuration:TimeInterval = 0.3
        let movement:CGFloat = ( up ? -moveValue : moveValue)
        UIView.beginAnimations( "animateView", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(movementDuration ) 
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }

1
@ Jogendra.Com, дякую за вашу наполегливу роботу. Але найкраще він працює на iPhone 5,4s та 6.Але як я можу відключити його на iPhone 6plus та iPad (більш високі)
Thiha Aung

Якщо ви використовуєте Варіант 1, будь ласка, не забудьте додати обмеження IBOutlet. Ви створите обмеження, яке хочете змінити за допомогою автоматичного макета, потім перетягніть його на панель перегляду, щоб створити IBOutlet, який я посилаю на нього як self.iboutletConstraint.constant у функції анімації. Крім того, це не повторно налаштовує розетку при приховуванні клавіатури, я вирішив, що скинувши обмеження на початкове значення.
Хаммад Тарік

21

Я люблю чистий код Свіфта. Тож ось найскладніший код, який я міг би придумати, щоб перемістити перегляд тексту вгору / вниз за допомогою клавіатури. В даний час працює у виробничому додатку iOS8 / 9 Swift 2.

ОНОВЛЕННЯ (березень 2016 р.): Я просто максимально посилив свій попередній код. Також тут є купа популярних відповідей, які жорстко кодують висоту клавіатури та параметри анімації. У цьому немає потреби, не кажучи вже про те, що цифри в цих відповідях не завжди узгоджуються з фактичними значеннями, які я бачу на своїх 6s + iOS9 (висота клавіатури 226, тривалість 0,25 і крива анімації 7). У будь-якому випадку, майже немає зайвого коду, щоб отримати ці значення прямо з системи. Дивись нижче.

override func viewDidLoad() {
    super.viewDidLoad()

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

func animateWithKeyboard(notification: NSNotification) {

    // Based on both Apple's docs and personal experience, 
    // I assume userInfo and its documented keys are available.
    // If you'd like, you can remove the forced unwrapping and add your own default values.

    let userInfo = notification.userInfo!
    let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
    let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
    let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
    let moveUp = (notification.name == UIKeyboardWillShowNotification)

    // baseContraint is your Auto Layout constraint that pins the
    // text view to the bottom of the superview.

    baseConstraint.constant = moveUp ? -keyboardHeight : 0

    let options = UIViewAnimationOptions(rawValue: curve << 16)
    UIView.animateWithDuration(duration, delay: 0, options: options,
        animations: {
            self.view.layoutIfNeeded()
        },
        completion: nil
    )

}

ПРИМІТКА. Цей код охоплює найбільш коментарі / загальні випадки. Однак для обробки різних орієнтацій та / або спеціальних клавіатур може знадобитися більше коду. Ось детальна стаття про роботу з клавіатурою iOS. Якщо вам потрібно впоратися з кожним сценарієм, це може допомогти.


Здається, це Swift 1.1, і я думаю, що не буде компілюватись у Swift 1.2, тому що він використовується asдля примусової ролі. as!може спрацювати, але як ви бачите в іншому місці на цій сторінці, я уникаю примусових закидів і сили розгортання.
Джозеф Лорд

Компілюється зараз у Swift 1.2. І я додав коментар до коду про: примусове розкручування. Ура.
scootermg

На жаль Я мав на увазі Свіфт 2.
Scootermg

Залежно від того, як ви пов’язали своє, baseConstraintце може бути baseConstraint.constant = moveUp ? keyboardHeight : 0замість baseConstraint.constant = moveUp ? -keyboardHeight : 0.
обмеження

15

Редагувати : Я рекомендую простіше і більш чисте рішення. Просто змініть клас обмежень між інтервалом внизу на KeyboardLayoutConstraint . Він автоматично розшириться до висоти клавіатури.


Це вдосконалена версія відповіді @JosephLord.

Як перевірено на iOS 8.3 iPad Simulator, Portrait. Xcode6.3 beta4, я виявив, що його відповідь не працює, коли клавіатура ховається, оскільки UIKeyboardFrameEndUserInfoKeyє "NSRect: {{0, 1024}, {768, 264}}";. Висота ніколи не буває 0.

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

    // You have to set this up in storyboard first!. 
    // It's a vertical spacing constraint between view and bottom of superview.
    @IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint! 

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillShowNotification, object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillHideNotification, object: nil);
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    func keyboardNotification(notification: NSNotification) {

        let isShowing = notification.name == UIKeyboardWillShowNotification

        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
            let endFrameHeight = endFrame?.size.height ?? 0.0
            let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            self.bottomSpacingConstraint?.constant = isShowing ? endFrameHeight : 0.0
            UIView.animateWithDuration(duration,
                delay: NSTimeInterval(0),
                options: animationCurve,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }
    }

Чи можете ви поясніть свою редакцію? Я не міг змусити його працювати. У мене є UIScrollView з кнопкою внизу. Я встановив клас із обмеженням на нижній частині поля.
schw4ndi

@ schw4ndi до яких поглядів пов'язані ваші нижні обмеження? він повинен з'єднувати нижній частині перегляду прокрутки до нижньої частини цього перегляду прокрутки.
Hlung

О, дякую, у мене було обмеження між кнопкою та scrollView
schw4ndi

9

Я працюю зі швидким 4, і я вирішую цю проблему без використання зайвих обмежень знизу. Подивіться, мій код тут. Це дійсно працює над моєю справою

1) Додати спостерігача сповіщень у зроблене завантаження

override func viewDidLoad() {
        super.viewDidLoad()
        setupManager()
        // Do any additional setup after loading the view.
        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)
    }

2) Видалити сповіщувача сповіщення, як

deinit {
        NotificationCenter.default.removeObserver(self)
    }

3) Додайте такі способи показу / приховування клавіатури, як

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

@objc func keyboardWillHide(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            UIView.animate(withDuration: 0.1, animations: { () -> Void in
                self.view.frame.origin.y += keyboardSize.height
                self.view.layoutIfNeeded()
            })
        }
    }

4) Додайте делегат textfeild та додайте touchsBegan методи .використовуйте для приховування клавіатури, коли торкаєтесь за межами textfeild на екрані

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

    }

потрібноUIKeyboardFrameEndUserInfoKey
Micro

1
NSNotification.Name.UIKeyboardWillShow перейменовується UIResponder.keyboardWillShowNotificationтакож UIKeyboardFrameBeginUserInfoKey доUIResponder.keyboardFrameBeginUserInfoKey
Smj

7

Це вдосконалена версія відповіді @JosephLord та @ Hlung. Він може застосовуватися, чи є у вас вкладка чи ні. І це чудово відновить вигляд, який переміщується клавіатурою у вихідне положення.

// You have to set this up in storyboard first!. 
// It's a vertical spacing constraint between view and bottom of superview.
@IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint! 

override func viewDidLoad() {
        super.viewDidLoad()            

        //    Receive(Get) Notification
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillHideNotification, object: nil)


        self.originalConstraint = self.keyboardHeightLayoutConstraint?.constant //for original coordinate.
}

func keyboardNotification(notification: NSNotification) {
        let isShowing = notification.name == UIKeyboardWillShowNotification

        var tabbarHeight: CGFloat = 0
        if self.tabBarController? != nil {
            tabbarHeight = self.tabBarController!.tabBar.frame.height
        }
        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
            let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            self.keyboardHeightLayoutConstraint?.constant = isShowing ? (endFrame!.size.height - tabbarHeight) : self.originalConstraint!
            UIView.animateWithDuration(duration,
                delay: NSTimeInterval(0),
                options: animationCurve,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }
}

6

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

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

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


2
Чудове рішення! Але вам потрібен Safe Area.Bottom як перший пункт обмеження (не працював для мене, коли це був другий пункт). І він найкраще працював з постійним значенням 0, оскільки він зберігає константу і коригує її, а не просто переміщуючи її досить далеко, щоб показати поле та клавіатуру.
Міфландія

Чи є у вас версія KeyboardLayoutConstraint swift4?
jeet.chanchawat

6

Я створив протокол Swift 3 для обробки появи / зникнення клавіатури

import UIKit

protocol KeyboardHandler: class {

var bottomConstraint: NSLayoutConstraint! { get set }

    func keyboardWillShow(_ notification: Notification)
    func keyboardWillHide(_ notification: Notification)
    func startObservingKeyboardChanges()
    func stopObservingKeyboardChanges()
}


extension KeyboardHandler where Self: UIViewController {

    func startObservingKeyboardChanges() {

        // NotificationCenter observers
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        // Deal with rotations
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        // Deal with keyboard change (emoji, numerical, etc.)
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextInputCurrentInputModeDidChange, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillHide(notification)
        }
    }


    func keyboardWillShow(_ notification: Notification) {

      let verticalPadding: CGFloat = 20 // Padding between the bottom of the view and the top of the keyboard

      guard let value = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
      let keyboardHeight = value.cgRectValue.height

      // Here you could have more complex rules, like checking if the textField currently selected is actually covered by the keyboard, but that's out of this scope.
      self.bottomConstraint.constant = keyboardHeight + verticalPadding

      UIView.animate(withDuration: 0.1, animations: { () -> Void in
          self.view.layoutIfNeeded()
      })
  }


  func keyboardWillHide(_ notification: Notification) {
      self.bottomConstraint.constant = 0

      UIView.animate(withDuration: 0.1, animations: { () -> Void in
          self.view.layoutIfNeeded()
      })
  }


  func stopObservingKeyboardChanges() {
      NotificationCenter.default.removeObserver(self)
  }

}

Потім, щоб реалізувати його в UIViewController, виконайте наступне:

  • нехай viewController відповідає цьому протоколу:

    class FormMailVC: UIViewControlle, KeyboardHandler {
  • почніть спостерігати за змінами клавіатури у viewWillAppear:

    // MARK: - View controller life cycle
    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
      startObservingKeyboardChanges()
    }
  • припиніть спостерігати за змінами клавіатури у viewWillDisappear:

    override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      stopObservingKeyboardChanges()
    }
  • створити IBOutlet для нижнього обмеження на аркуші розкадрування:

    // NSLayoutConstraints
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!

    (Рекомендую весь свій інтерфейс вбудувати у "contentView" та прив'язати до цього властивості нижнє обмеження з цього contentView до нижнього посібника з макета) Нижнє обмеження перегляду вмісту

  • змінити пріоритет обмеження верхнього обмеження на 250 (низьке)

Основне обмеження для перегляду вмісту

Це означає, щоб весь перегляд вмісту ковзав догори, коли з'являється клавіатура. Пріоритет повинен бути нижчим, ніж будь-який інший пріоритет обмежень у підзаглядах, включаючи пріоритети захоплення вмісту / пріоритети стійкості до стиснення вмісту.

  • Переконайтеся, що у вашому автоматичному розкладі є достатньо обмежень, щоб визначити, яким чином має перейти зміст ViewView.

Для цього вам, можливо, доведеться додати обмеження "більше, ніж рівне": обмеження "більше, ніж рівне"

І ось ви йдете! Без клавіатури

З клавіатурою


Це працює, якщо ви також ставите "Відносини = рівні", без попереджень.
Валтоні Боавентура

Якщо ви ставите рівноправні відносини, це може спрацювати лише в конкретних ситуаціях. В інших може виникнути попередження про невідповідність автоматичного макета. Це залежить від вашого власного макета. Ось чому я сказав "ти можеш".
Фредерік Адда

Добре Фредерік, погодився. Було приємне рішення!
Валтоні Боавентура

зник безвістиimport UIKit
Мирко

6

Таке просте UIViewController розширення можна використовувати

//MARK: - Observers
extension UIViewController {

    func addObserverForNotification(notificationName: String, actionBlock: (NSNotification) -> Void) {
        NSNotificationCenter.defaultCenter().addObserverForName(notificationName, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: actionBlock)
    }

    func removeObserver(observer: AnyObject, notificationName: String) {
        NSNotificationCenter.defaultCenter().removeObserver(observer, name: notificationName, object: nil)
    }
}

//MARK: - Keyboard observers
extension UIViewController {

    typealias KeyboardHeightClosure = (CGFloat) -> ()

    func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
        willHide willHideClosure: KeyboardHeightClosure?) {
            NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillChangeFrameNotification,
                object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: { [weak self](notification) in
                    if let userInfo = notification.userInfo,
                        let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue(),
                        let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
                        let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
                        let kFrame = self?.view.convertRect(frame, fromView: nil),
                        let kBounds = self?.view.bounds {

                            let animationType = UIViewAnimationOptions(rawValue: c)
                            let kHeight = kFrame.size.height
                            UIView.animateWithDuration(duration, delay: 0, options: animationType, animations: {
                                if CGRectIntersectsRect(kBounds, kFrame) { // keyboard will be shown
                                    willShowClosure?(kHeight)
                                } else { // keyboard will be hidden
                                    willHideClosure?(kHeight)
                                }
                                }, completion: nil)
                    } else {
                            print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                    }
            })
    }

    func removeKeyboardObserver() {
        removeObserver(self, notificationName: UIKeyboardWillChangeFrameNotification)
    }
}

Приклад використання

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

        removeKeyboardObserver()
    }

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

    addKeyboardChangeFrameObserver(willShow: { [weak self](height) in
        //Update constraints here
        self?.view.setNeedsUpdateConstraints()
        }, willHide: { [weak self](height) in
        //Reset constraints here
        self?.view.setNeedsUpdateConstraints()
    })
}

Рішення Swift 4

//MARK: - Observers
extension UIViewController {

  func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) {
    NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock)
  }

  func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) {
    NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil)
  }
}

//MARK: - Keyboard handling
extension UIViewController {

  typealias KeyboardHeightClosure = (CGFloat) -> ()

  func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
                                      willHide willHideClosure: KeyboardHeightClosure?) {
    NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame,
                                           object: nil, queue: OperationQueue.main, using: { [weak self](notification) in
                                            if let userInfo = notification.userInfo,
                                              let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
                                              let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
                                              let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
                                              let kFrame = self?.view.convert(frame, from: nil),
                                              let kBounds = self?.view.bounds {

                                              let animationType = UIViewAnimationOptions(rawValue: c)
                                              let kHeight = kFrame.size.height
                                              UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: {
                                                if kBounds.intersects(kFrame) { // keyboard will be shown
                                                  willShowClosure?(kHeight)
                                                } else { // keyboard will be hidden
                                                  willHideClosure?(kHeight)
                                                }
                                              }, completion: nil)
                                            } else {
                                              print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                                            }
    })
  }

  func removeKeyboardObserver() {
    removeObserver(self, notificationName: NSNotification.Name.UIKeyboardWillChangeFrame)
  }
}

Швидкий 4.2

//MARK: - Keyboard handling
extension UIViewController {

    func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) {
        NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock)
    }

    func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) {
        NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil)
    }

    typealias KeyboardHeightClosure = (CGFloat) -> ()

    func removeKeyboardObserver() {
        removeObserver(self, notificationName: UIResponder.keyboardWillChangeFrameNotification)
    }

    func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
                                        willHide willHideClosure: KeyboardHeightClosure?) {
        NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification,
                                               object: nil, queue: OperationQueue.main, using: { [weak self](notification) in
                                                if let userInfo = notification.userInfo,
                                                    let frame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
                                                    let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double,
                                                    let c = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt,
                                                    let kFrame = self?.view.convert(frame, from: nil),
                                                    let kBounds = self?.view.bounds {

                                                    let animationType = UIView.AnimationOptions(rawValue: c)
                                                    let kHeight = kFrame.size.height
                                                    UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: {
                                                        if kBounds.intersects(kFrame) { // keyboard will be shown
                                                            willShowClosure?(kHeight)
                                                        } else { // keyboard will be hidden
                                                            willHideClosure?(kHeight)
                                                        }
                                                    }, completion: nil)
                                                } else {
                                                    print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                                                }
        })
    }
}

2
набагато більше "Швидкого", ніж інші рішення / працює чудово / багаторазово використовується в кожному контролері, не переписуючи все -> безумовно, найкраще тут :)
Тіб

Я спробував, але немає шансів, потрібен UIScrollView чи що?
erdemgc

@erdemgc Ви бачили Приклад використання? Все, що вам потрібно, це просто UIViewControlller + addKeyboardChangeFrameObserver, а потім не забудьте його видалити
ale_stro

removeKeyboardObserver()Метод тут не видаляє спостерігача. Якщо ви цього не зателефонували, ви побачите Invalid conditions for UIKeyboardWillChangeFrameNotificationна консолі від методу add. Якщо ви зателефонуєте цьому, ви побачите ту саму помилку, тобто спостерігач не видалений. У документації зазначено "Для незареєстрування спостережень ви передаєте об'єкт, повернутий цим методом removeObserver(_:)." Тож те, що ти робиш замість цього, зберігає об’єкт, повернутий цим методом, а потім передаєш його, коли потрібно видалити спостерігача.
Хуй-Ань Хоанг

Насправді, щойно перегляд прокрутки завантажується, прив’язаному призначається значення, і ви не можете визначити, чи буде прихована клавіатура, якщо рамка клавіатури перетинається з пов'язаною.
Джеймс Кім

5

Ви можете використовувати цю бібліотеку і лише один рядок коду в appDidFinishedLaunching і виконано.

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

    IQKeyboardManager.sharedManager().enable = true
    return true
}

IQKeyboardManager - регулює перегляд кожного разу, коли з'являється посилання на клавіатурі - https://github.com/hackiftekhar/IQKeyboardManager


4
struct MoveKeyboard {
    static let KEYBOARD_ANIMATION_DURATION : CGFloat = 0.3
    static let MINIMUM_SCROLL_FRACTION : CGFloat = 0.2;
    static let MAXIMUM_SCROLL_FRACTION : CGFloat = 0.8;
    static let PORTRAIT_KEYBOARD_HEIGHT : CGFloat = 216;
    static let LANDSCAPE_KEYBOARD_HEIGHT : CGFloat = 162;
}


  func textFieldDidBeginEditing(textField: UITextField) {
    let textFieldRect : CGRect = self.view.window!.convertRect(textField.bounds, fromView: textField)
    let viewRect : CGRect = self.view.window!.convertRect(self.view.bounds, fromView: self.view)

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

    if heightFraction < 0.0 {
        heightFraction = 0.0
    } else if heightFraction > 1.0 {
        heightFraction = 1.0
    }

    let orientation : UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown) {
        animateDistance = floor(MoveKeyboard.PORTRAIT_KEYBOARD_HEIGHT * heightFraction)
    } else {
        animateDistance = floor(MoveKeyboard.LANDSCAPE_KEYBOARD_HEIGHT * heightFraction)
    }

    var viewFrame : CGRect = self.view.frame
    viewFrame.origin.y -= animateDistance

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))

    self.view.frame = viewFrame

    UIView.commitAnimations()
}


func textFieldDidEndEditing(textField: UITextField) {
    var viewFrame : CGRect = self.view.frame
    viewFrame.origin.y += animateDistance

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)

    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))

    self.view.frame = viewFrame

    UIView.commitAnimations()

}

І нарешті, оскільки ми використовуємо методи делегатів

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

відновлюється від використання цілі-c http://www.cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html


Це рішення працювало для мене, хоча мені довелося виконати додаткову роботу: оголосити var animateDistance: CGFloat!плюс, мені довелося обробляти UIKeyboardWillHideNotification, коли користувач натискає кнопку приховати клавіатуру.
Rhuantavan

4

Ще одне рішення, яке не залежить від автоматичного розкладу, обмежень або будь-яких торгових точок. Що вам потрібно, це ваші поля в прокрутці.

override func viewDidLoad() {
    super.viewDidLoad()

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

func makeSpaceForKeyboard(notification: NSNotification) {
    let info = notification.userInfo!
    let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
    let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double

    if notification.name == UIKeyboardWillShowNotification {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height - keyboardHeight
            self.view.frame = frame
        })
    } else {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height + keyboardHeight
            self.view.frame = frame
        })
    }

}

1
На ньому відображається чорний екран після UIKeyboardWillShowNotificationдзвінка.
Сачин Кумарам

4

Ось моя версія для рішення Swift 2.2:

Перший реєстр для клавіатури Показати / приховати сповіщення

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

Потім методами, що відповідають цим сповіщенням, переміщуйте основний вид вгору або вниз

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

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

Хитрість полягає в частині "keyboardWillShow", яка отримує дзвінки щоразу, коли "Штрих пропозицій QuickType" розширюється або згортається. Тоді ми завжди встановлюємо y координату головного виду, що дорівнює від'ємному значенню загальної висоти клавіатури (з або без частини "Штрих-панелі" частина).

Наприкінці не забудьте зняти спостерігачів

deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}

3

Далі наведено просте рішення, згідно з яким текстове поле має обмеження, прив’язуючи його до нижнього посібника макета. Він просто додає висоту клавіатури постійному обмеження.

// This constraint ties the text field to the bottom layout guide
@IBOutlet var textFieldToBottomLayoutGuideConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()

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

func keyboardWillShow(sender: NSNotification) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.textFieldToBottomLayoutGuideConstraint?.constant += keyboardSize.height
    }
}

func keyboardWillHide(sender: NSNotification) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.textFieldToBottomLayoutGuideConstraint?.constant -= keyboardSize.height
    }
}

3

Ну, я думаю, я можу запізнитися, але я знайшов іншу просту версію відповіді Сакіба. Я використовую функцію Autolayout з обмеженнями. У мене невеликий вигляд іншого головного подання з полями імені користувача та пароля. Замість зміни координати y подання я зберігаю початкове значення обмеження в змінній і змінюю константу обмеження на деяке значення, і знову після відхилення клавіатури я встановлюю обмеження на початкове. Таким чином, це дозволяє уникнути проблеми відповіді Сакіба, (погляд продовжує рухатися вгору і не припиняється). Нижче мій код ...

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);
    self.originalConstraint = self.centerYConstraint.constant
  }

  func keyboardWillShow(sender: NSNotification) {
    self.centerYConstraint.constant += 30
  }

  func keyboardWillHide(sender: NSNotification) {
    self.centerYConstraint.constant = self.originalConstraint
  }

Внутрішня клавіатураWillShow метод перевірить стан, якщо self.centerYConstraint.constant == self.originalCenterYConstraint тоді має один рядок коду між цією умовою. OriginalCenterYContraint - це вихідне значення центруYContraint, яке я зберігаю у перегляді завантаження. Це працювало для мене.
Саші

3

Відповідь Swift 4.x, злиття відповідей від @Joseph Lord та @Isuru. bottomConstraintявляє собою нижнє обмеження перегляду, яке ви хочете перенести.

override func viewDidLoad() {
    // Call super
    super.viewDidLoad()

    // Subscribe to keyboard notifications
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(keyboardNotification(notification:)),
                                           name: UIResponder.keyboardWillChangeFrameNotification,
                                           object: nil)        
}


deinit {
    NotificationCenter.default.removeObserver(self)
}


@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        // Get keyboard frame
        let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

        // Set new bottom constraint constant
        let bottomConstraintConstant = keyboardFrame.origin.y >= UIScreen.main.bounds.size.height ? 0.0 : keyboardFrame.size.height

        // Set animation properties
        let duration = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve = UIView.AnimationOptions(rawValue: animationCurveRaw)

        // Animate the view you care about
        UIView.animate(withDuration: duration, delay: 0, options: animationCurve, animations: {
            self.bottomConstraint.constant = bottomConstraintConstant
            self.view.layoutIfNeeded()
        }, completion: nil)
    }
}

2

Я зробив наступним чином:

Це корисно при перегляді текстового поля

class AdminLoginViewController: UIViewController,
UITextFieldDelegate{

    @IBOutlet weak var txtUserName: UITextField!
    @IBOutlet weak var txtUserPassword: UITextField!
    @IBOutlet weak var btnAdminLogin: UIButton!

    private var activeField : UIView?

    var param:String!
    var adminUser : Admin? = nil
    var kbHeight: CGFloat!

    override func viewDidLoad()
    {
        self.addKeyBoardObserver()
        self.addGestureForHideKeyBoard()
    }

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

    func addGestureForHideKeyBoard()
    {
        let tapGesture = UITapGestureRecognizer(target: self, action: Selector("hideKeyboard"))
        tapGesture.cancelsTouchesInView = false
        view.addGestureRecognizer(tapGesture)
    }

    func hideKeyboard() {
        self.view.endEditing(true)
    }

    func addKeyBoardObserver(){

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

    func removeObserver(){
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    //MARK:- textfiled Delegate

    func textFieldShouldBeginEditing(textField: UITextField) -> Bool
    {
         activeField = textField

        return true
    }
    func textFieldShouldEndEditing(textField: UITextField) -> Bool
    {
        if activeField == textField
        {
            activeField = nil
        }

        return true
    }

    func textFieldShouldReturn(textField: UITextField) -> Bool {

        if txtUserName == textField
        {
            txtUserPassword.becomeFirstResponder()
        }
        else if (textField == txtUserPassword)
        {
            self.btnAdminLoginAction(nil)
        }
        return true;
    }

    func willChangeKeyboardFrame(aNotification : NSNotification)
    {
       if self.activeField != nil && self.activeField!.isFirstResponder()
    {
        if let keyboardSize =  (aNotification.userInfo![UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
        {
            let dy = (self.activeField?.superview?.convertRect((self.activeField?.frame)!, toView: view).origin.y)!

            let height = (self.view.frame.size.height - keyboardSize.size.height)

            if dy > height
            {
                var frame = self.view.frame

                frame.origin.y = -((dy - height) + (self.activeField?.frame.size.height)! + 20)

                self.view.frame = frame
            }
        }
    }
    else
    {
        var frame = self.view.frame
        frame.origin.y = 0
        self.view.frame = frame
    }
    } }

2
    func registerForKeyboardNotifications(){
        //Keyboard
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWasShown), name: UIKeyboardDidShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillBeHidden), name: UIKeyboardDidHideNotification, object: nil)


    }
    func deregisterFromKeyboardNotifications(){

        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)

    }
    func keyboardWasShown(notification: NSNotification){

        let userInfo: NSDictionary = notification.userInfo!
        let keyboardInfoFrame = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue()

        let windowFrame:CGRect = (UIApplication.sharedApplication().keyWindow!.convertRect(self.view.frame, fromView:self.view))

        let keyboardFrame = CGRectIntersection(windowFrame, keyboardInfoFrame!)

        let coveredFrame = UIApplication.sharedApplication().keyWindow!.convertRect(keyboardFrame, toView:self.view)

        let contentInsets = UIEdgeInsetsMake(0, 0, (coveredFrame.size.height), 0.0)
        self.scrollViewInAddCase .contentInset = contentInsets;
        self.scrollViewInAddCase.scrollIndicatorInsets = contentInsets;
        self.scrollViewInAddCase.contentSize = CGSizeMake((self.scrollViewInAddCase.contentSize.width), (self.scrollViewInAddCase.contentSize.height))

    }
    /**
     this method will fire when keyboard was hidden

     - parameter notification: contains keyboard details
     */
    func keyboardWillBeHidden (notification: NSNotification) {

        self.scrollViewInAddCase.contentInset = UIEdgeInsetsZero
        self.scrollViewInAddCase.scrollIndicatorInsets = UIEdgeInsetsZero

    }

1
Використовуйте наведений вище код, щоб швидко перемістити текстове поле над клавіатурою, воно буде добре. Я сподіваюся, що це допоможе комусь.
Kamalkumar.E

1

Я зробив наступним чином:

class SignInController: UIViewController , UITextFieldDelegate {

@IBOutlet weak var scrollView: UIScrollView!

// outlet declartion
@IBOutlet weak var signInTextView: UITextField!

var kbHeight: CGFloat!

/**
*
* @method viewDidLoad
*
*/

override func viewDidLoad() {
    super.viewDidLoad()

    self.signInTextView.delegate = self

}// end viewDidLoad

/**
*
* @method viewWillAppear
*
*/

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

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

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

}// end viewWillAppear

/**
*
* @method viewDidAppear
*
*/

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


}// end viewDidAppear

/**
*
* @method viewWillDisappear
*
*/
override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

/**
*
* @method textFieldShouldReturn
* retun the keyboard value
*
*/

// MARK -
func textFieldShouldReturn(textField: UITextField) -> Bool {
    signInTextView.resignFirstResponder()
    return true;

}// end textFieldShouldReturn

// MARK - keyboardWillShow
func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardSize =  (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            kbHeight = keyboardSize.height
            self.animateTextField(true)
        }
    }
}// end keyboardWillShow

// MARK - keyboardWillHide
func keyboardWillHide(notification: NSNotification) {
    self.animateTextField(false)
}// end keyboardWillHide

// MARK - animateTextField
func animateTextField(up: Bool) {
    var movement = (up ? -kbHeight : kbHeight)

    UIView.animateWithDuration(0.3, animations: {
        self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    })
}// end animateTextField

/**
*
* @method didReceiveMemoryWarning
*
*/

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.

}// end didReceiveMemoryWarning


}// end SignInController

1

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

  1. У моєму випадку IQkeyboardmanager працював лише тоді, коли на елементах не застосовується автоматична компоновка, якщо вона застосована, то менеджер IQkeyboard не працюватиме так, як ми думаємо.
  2. Те саме з рухом вгору самовідвідування вгору.
  3. я написав об'єктивний заголовок c зі швидкою підтримкою для підштовхування UITexfield вгору, коли користувач натискає на нього, вирішуючи проблему клавіатури, що охоплює UITextfield: https://github.com/coolvasanth/smart_keyboard .
  4. Той, хто має проміжний або вищий рівень в розробці додатків для iOS, може легко зрозуміти сховище та реалізувати його. Всього найкращого

1

Ось загальне рішення для всіх кроків TextField -

1) Створіть загальний ViewController, який розширюється іншими ViewControllers

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.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= getMoveableDistance(keyboarHeight: keyboardSize.height)
        }
    }
}

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

//get the distance to move up the main view for the focus textfiled
func getMoveableDistance(keyboarHeight : CGFloat) ->  CGFloat{
    var y:CGFloat = 0.0
    if let activeTF = getSelectedTextField(){
        var tfMaxY = activeTF.frame.maxY
        var containerView = activeTF.superview!
        while containerView.frame.maxY != self.view.frame.maxY{
            let contViewFrm = containerView.convert(activeTF.frame, to: containerView.superview)
            tfMaxY = tfMaxY + contViewFrm.minY
            containerView = containerView.superview!
        }
        let keyboardMinY = self.view.frame.height - keyboarHeight
        if tfMaxY > keyboardMinY{
            y = (tfMaxY - keyboardMinY) + 10.0
        }
    }

    return y
}

2) Створіть розширення UIViewController та поточно активне TextField

//get active text field

розширення UIViewController {func getSelectedTextField () -> UITextField? {

    let totalTextFields = getTextFieldsInView(view: self.view)

    for textField in totalTextFields{
        if textField.isFirstResponder{
            return textField
        }
    }

    return nil

}

func getTextFieldsInView(view: UIView) -> [UITextField] {

    var totalTextFields = [UITextField]()

    for subview in view.subviews as [UIView] {
        if let textField = subview as? UITextField {
            totalTextFields += [textField]
        } else {
            totalTextFields += getTextFieldsInView(view: subview)
        }
    }

    return totalTextFields
}

}


Чомусь у мене виникли проблеми з функцією клавіатуриWillShow, розмір клавіатури набував неправильного розміру після першого перемикання клавіатури (перший перемикач має правильний кадр). Я це виправив, змінивши його, щоб захистити, нехай userInfo = noti.userInfo else {return} охороняє дозволяють keyboardSize = userInfo [UIResponder.keyboardFrameEndUserInfoKey] як? NSValue else {return} нехай клавіатураFrame = keyboardSize.cgRectValue, якщо self.view.frame.origin.y == 0 {self.view.frame.origin.y - = getMoveableDistance (keyboarHeight: keyboardFrame.height)}. Надію це допоможе. якщо хтось отримав те саме питання :)
Youstanzr

1

Дуже просто і не потрібно більше кодувати. Просто додайте pod 'IQKeyboardManagerSwift'у свій підфайл, а на своїй AppDelegateсторінці додайте код нижче.

import IQKeyboardManagerSwift

і за didFinishLaunchingWithOptions()типом методу

IQKeyboardManager.shared.enable = true

це все. перевірте це посилання на відео для кращого розуміння https://youtu.be/eOM94K1ZWN8 Сподіваюся, що це вам допоможе.


Чи працює це для TextView і як я можу змінити назву для ключа повернення "Готово"?
tdt kien

Goto: - "IQKeyboardManager.m" Замінити цю лінію (Line No. 968): - [TextField addDoneOnKeyboardWithTarget: сама дія: @selector (doneAction :) shouldShowPlaceholder: _shouldShowTextFieldPlaceholder] з цим: - [TextField addRightButtonOnKeyboardWithText: @ "YOURTEXT" мета: самодія: @selector (doneAction :) повиненShowPlaceholder: _shouldShowTextFieldPlaceholder]; І ще не пробували для перегляду тексту, сподіваюся, це допоможе вам.
Рагіб Арші

1

Повний код управління клавіатурою.

        override func viewWillAppear(_ animated: Bool) {
            NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        override func viewWillDisappear(_ animated: Bool) {
            NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        @objc func keyboardWillShow(notification: NSNotification) {
            guard let userInfo = notification.userInfo else {return}
            guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {return}
            let keyboardFrame = keyboardSize.cgRectValue

            if self.view.bounds.origin.y == 0{
                self.view.bounds.origin.y += keyboardFrame.height
            }
        }


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

0

Я трохи змінив рішення @Simpa .........

override func viewDidLoad() 
{

    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillHideNotification, object: nil);
}

deinit{
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

var keyboardIsVisible = false
override func makeSpaceForKeyboard(notification: NSNotification) {

    let info = notification.userInfo!
    let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
    let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double

    if notification.name == UIKeyboardWillShowNotification && keyboardIsVisible == false{

        keyboardIsVisible = true

        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height - keyboardHeight
            self.view.frame = frame
        })

    } else if keyboardIsVisible == true && notification.name == UIKeyboardWillShowNotification{

    }else {
        keyboardIsVisible = false

        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height + keyboardHeight
            self.view.frame = frame
        })
    }
}

0

Жоден з них не працював, і я в кінцевому підсумку використовував вставки вмісту, щоб перемістити свій погляд вгору, коли з’являється клавіатура.

Примітка: Я використовував UITableView

Посилання на рішення @ компенсація змісту клавіатури яке повністю було написано в цілі C, наведене нижче рішення є чистим Swift.

Додати спостерігача сповіщень @ viewDidLoad ()

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeShown), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeHidden), name:UIKeyboardWillHideNotification, object: nil);

Щоб отримати розмір клавіатури, ми спочатку отримуємо словник userInfo від об’єкта сповіщення, який зберігає будь-які додаткові об’єкти, якими може користуватися наш приймач.

З цього словника ми можемо отримати об'єкт CGRect, що описує рамку клавіатури, використовуючи клавішу UIKeyboardFrameBeginUserInfoKey.

Застосуйте вставку вмісту для перегляду таблиці @ methodWillBeShown,

func keyboardWillBeShown(sender: NSNotification)
{        
    // Move the table view

    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
    {
        let contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);

        yourTableView.contentInset = contentInsets;

        yourTableView.scrollIndicatorInsets = contentInsets;
    }
}

Відновіть метод перегляду @ keyboardWillBeHidden

func keyboardWillBeHidden(sender: NSNotification)
{
    // Moving back the table view back to the default position

    yourTableView.contentInset = UIEdgeInsetsZero;

    yourTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
}

Якщо ви хочете також врахувати орієнтацію пристрою, використовуйте умовні висловлювання, щоб підлаштувати код під свої потреби.

// Portrait
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);

// Landscape
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.width), 0.0);

0
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

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

func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
    }
}

func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    }
}

введіть тут опис зображення


0

Я використовую рішення Swift 4, розмір клавіатури. Замініть serverStatusStackViewбудь-який вид, який вас хвилює, наприклад self.view:

deinit {
    NotificationCenter.default.removeObserver(self)
}

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

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        serverStatusStackView.frame.origin.y += keyboardSize.height
    }
}

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

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

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