Spostare la vista con la tastiera utilizzando Swift


278

Ho un'app che ha un campo di testo nella metà inferiore della vista. Ciò significa che quando vado a digitare nel campo di testo la tastiera copre il campo di testo.

Come potrei spostare la vista verso l'alto durante la digitazione in modo da poter vedere quello che sto scrivendo e poi spostarlo nella sua posizione originale quando la tastiera scompare?

Ho cercato ovunque, ma tutte le soluzioni sembrano essere in Obj-C che non riesco ancora a convertire.

Qualsiasi aiuto sarebbe molto apprezzato.


Il modo migliore per farlo è posizionare il contenuto all'interno di un UIScrollView , quindi regolare la proprietà contentInset della vista di scorrimento in base all'altezza della tastiera quando viene visualizzata. Assolutamente non assumere l'altezza della tastiera - usa il valore della notifica "tastiera mostrerà".
nielsbot,

1
In effetti, i documenti di Apple ti spiegano come farlo, in "Gestione della tastiera": developer.apple.com/library/ios/documentation/StringsTextFonts/…
nielsbot

11
Penso che tutte le risposte qui sotto non prendano in considerazione un caso: cosa succede se hai più campi di testo e alcuni di essi si trovano nella parte superiore dello schermo? Ogni volta che l'utente tocca quel campo di testo, sale oltre lo schermo, sono abbastanza sicuro che la risposta corretta dovrebbe rilevare seit is actually needed to scroll view up when keyboard appears
DC

Questa risposta è in grado di rilevare se è effettivamente necessario per far scorrere la vista quando la tastiera appare verificando se il campo di testo attualmente in fase di modifica occupa lo stesso spazio come la tastiera: stackoverflow.com/a/28813720/6749410
HirdayGupta

Risposte:


710

Ecco una soluzione, senza gestire il passaggio da un campo di testo a un altro:

 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
}

Per risolvere questo, sostituire le due funzioni keyboardWillShow/Hidecon queste:

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

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

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

MODIFICA PER 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
Se l'utente tocca un altro campo di testo mentre è presente la tastiera, la vista verrà spostata più in alto, causando un'area nera (la dimensione della tastiera) - dobbiamo risolvere il problema avendo una variabile che traccia se la tastiera è presente o meno . ad es. se keyboardPresent == true non spostare l'origine della vista, ecc. ecc.
jonprasetyo,

3
@Matthew Lin usa un booleano, quindi le funzioni keyboardWillShow e hide funzionano solo una volta
iluvatar_GR

11
Solo un suggerimento, in modo da non dover eseguire il debug molto come ho fatto io. Se hai più campi uitext sullo stesso schermo, la dimensione della tastiera può variare (non mostra suggerimenti per alcuni input in base alle tue impostazioni), quindi è consigliabile impostare self.view.frame.origin.y = 0, ogni volta chiudi la tastiera. Ad esempio, mostrerebbe le sugeestions per il tuo campo di testo e-mail, quindi le dimensioni della tastiera aumenterebbero e non mostrerebbe suggerimenti per il campo password, quindi le dimensioni della tastiera diminuiranno.
Vandan Patel,

36
È necessario utilizzare UIKeyboardFrameEndUserInfoKeyanziché UIKeyboardFrameBeginUserInfoKeyper ottenere le dimensioni della tastiera. Non sono sicuro del perché al momento, ma il primo produrrà risultati più coerenti.
jshapy8,

3
Si prega di sostituire UIKeyboardFrameBeginUserInfoKeycon UIKeyboardFrameEndUserInfoKey. Il primo dà il frame iniziale della tastiera, che a volte arriva a zero, mentre il secondo dà il frame finale della tastiera.
Arnab

90

Il modo più semplice che non richiede nemmeno alcun codice:

  1. Scarica KeyboardLayoutConstraint.swift e aggiungi (trascina e rilascia) il file nel tuo progetto, se non stai già utilizzando il framework di animazione Spring.
  2. Nello storyboard, crea un vincolo inferiore per la vista o il campo di testo, seleziona il vincolo (fai doppio clic su di esso) e in Identity Inspector, cambia la sua classe da NSLayoutConstraint a KeyboardLayoutConstraint.
  3. Fatto!

L'oggetto si sposterà automaticamente verso l'alto con la tastiera, in sincronia.


4
Per selezionare il vincolo inferiore puoi anche andare su Impostazioni dimensioni, quindi fare doppio clic sul vincolo nell'elenco - raywenderlich.com/wp-content/uploads/2015/09/…
gammachill

3
Questo ha funzionato perfettamente per me. è letteralmente un processo in 2 fasi. 1. Aggiungi KeyboardLayoutConstraint.swift, 2. Nello storyboard, crea un vincolo inferiore per la vista o il campo di testo. NOTA: ho eliminato i miei vincoli e aggiunto solo 1 vincolo in fondo alla vista o al campo di testo e ho cambiato la sua classe da NSLayoutConstraint a KeyboardLayoutConstraint. Quindi tutte le viste / campi di testo ecc. Sopra ho appena collegato i vincoli da quell'elemento all'elemento con un singolo KeyboardLayoutConstraint e il risultato è stato che tutti gli elementi in vista sono stati spostati SU / GIÙ quando la tastiera appare / scompare
Brian

4
Questa è la soluzione migliore, il codice fornito non codifica alcun valore come la lunghezza o la curva dell'animazione o la dimensione della tastiera. È anche facile da capire.
miguelSantirso,

3
Questo funziona per me, ma ho uno spazio extra di 50 px tra la parte superiore della tastiera e la parte inferiore di scrollView. Mi chiedo se sia dovuto al vincolo di fondo dell'area sicura che sto usando. Qualcuno ha incontrato questo?
Clifton Labrum,

1
Questa è stata una risposta fantastica. Design molto interessante. Un suggerimento: se le tue visualizzazioni di testo / campi di testo si trovano nelle celle della vista tabella, potresti notare che le viste che hanno questo vincolo salteranno goffamente ogni volta che l'utente fa clic su entra e passa al campo di testo successivo. Puoi avvolgere le animazioni DispatchQueue.main.async {}per risolverlo. Buon lavoro! Pollice su!
ScottyBlades

68

Una delle risposte più popolari su questo thread utilizza il seguente codice:

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

C'è un ovvio problema con la compensazione della vista di un importo statico. Apparirà bello su un dispositivo ma apparirà male su qualsiasi configurazione di altre dimensioni. Dovrai ottenere l'altezza della tastiera e usarla come valore di offset.

Ecco una soluzione che funziona su tutti i dispositivi e gestisce il caso limite in cui l'utente nasconde il campo di testo predittivo durante la digitazione.

Soluzione

Importante notare di seguito, stiamo passando self.view.window come parametro dell'oggetto. Questo ci fornirà i dati della nostra tastiera, come la sua altezza!

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

Lo renderemo bello su tutti i dispositivi e gestiremo il caso in cui l'utente aggiunge o rimuove il campo di testo predittivo.

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

Rimuovi osservatori

Non dimenticare di rimuovere i tuoi osservatori prima di lasciare la vista per impedire la trasmissione di messaggi non necessari.

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

Aggiornamento basato sulla domanda dei commenti:

Se hai due o più campi di testo, puoi verificare se view.frame.origin.y è a zero.

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
quando si ha a che fare con più campi di testo, la vista continua a spostarsi e non ritorna giù
Mugunthan Balakrishnan,

Dovrai cambiare le tue condizioni per tenere conto dei campi di testo
Dan Beaulieu,

grazie per la risposta, ho trovato la risposta che cercavo in questa discussione su Stack Overflow stackoverflow.com/questions/1126726/...
Mugunthan Balakrishnan

@MugunthanBalakrishnan grazie per averlo sollevato, ho aggiunto una soluzione.
Dan Beaulieu,

Ciao ragazzi, c'è un bug. Gli osservatori non vengono rimossi dalla vista dopo essere stati richiamati in viewWillDisappear. Sostituisci questa riga "NSNotificationCenter.defaultCenter (). RemoveObserver (self, nome: UIKeyboardWillHideNotification, oggetto: self.view.window)" con "NSNotificationCenter.defaultCenter (). RemoveObserver (self, nome: UIKeyboardWillHideNotification, oggetto: nil)" quindi osservatore viene rimosso
rudald

29

Aggiungi questo al tuo viewcontroller. Funziona come un fascino. Basta regolare i valori.

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
}

Questo funziona per me. Tuttavia è un po 'a scatti. Come posso ottenere questo per spostarmi su liscio? c'è anche un modo per applicarlo solo a uno dei campi di testo poiché attualmente lo fa per tutti. :(
DannieCoderBoi

2
Potrebbe non funzionare con "Auto-Layout", quindi considera di disattivarlo.
Teodor Ciuraru,

1
Causa un comportamento funky con autolayout @Josh, ti sbagli
Mike

5
Non farlo! Non puoi supporre che la tastiera abbia una certa dimensione.
nielsbot,

2
Dovrebbe usare keyboardSize. Cosa succede quando si hanno viste accessorie e altezze di tastiera diverse sui dispositivi? Tastiera staccata?
xtrinch,

25

Ho migliorato un po 'una delle risposte per farlo funzionare con diverse tastiere e diversi campi / visualizzazioni di testo su una pagina:

Aggiungi osservatori:

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

Rimuovi osservatori:

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
questa soluzione funziona meglio della risposta accettata. La risposta accettata mostra la tastiera solo una volta che per me è un bug :)
Masih,

Funziona con Xcode 10.1 e iOS 12. La risposta accettata non è più valida.
zeeshan,

Questa è una risposta eccellente, l'unica cosa che aggiungerei è tenere traccia dell'area di sicurezza inferiore nei dispositivi più recenti (X, XS, ecc.) In modo da renderlo conto.
Munib,

@Munib Vedi stackoverflow.com/a/54993623/1485230 Altre questioni includono la vista non l'animazione e il cambiamento altezza della tastiera non essere seguito.
Antzi,

cosa succede se il mio textField è in cima alla vista ..? intendo se esiste un campo di testo con origine Y = 0 .. ?? poi textField sta salendo e non riesco a vederlo
Saifan Nadaf,

19

Non una pubblicità o promozione o spam , solo una buona soluzione. So che questa domanda ha quasi 30 risposte e sono così scioccato che nessuno ha nemmeno menzionato una volta questo bellissimo progetto GitHub che fa tutto per te e anche meglio. Tutte le risposte spostano semplicemente la vista verso l'alto. Ho appena risolto tutti i miei problemi con questo IQKeyboardManager. Ha più di 13000 stelle.
Aggiungilo nel tuo podfile se stai usando swift

pod 'IQKeyboardManagerSwift'

e poi all'interno di AppDelegate.swift do 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
    }
}

Aggiungi la linea IQKeyboardManager.shared.enable = trueper abilitarlo
Questa soluzione è un must se stai andando per la produzione.


Questo è davvero buono, ma l'ultima versione non funziona per me, ho usato 6.2.1 e importato come import IQKeyboardManagere usato IQKeyboardManager.shared().isEnabled = truein AppDelegate
Dhanu K

2
E questo funziona perfettamente quando si usano più testi di modifica, Questo mi ha fatto risparmiare tempo
Dhanu K

1
Non posso ringraziare abbastanza per aver sottolineato questa meravigliosa biblioteca. Questa libreria è finalmente LA RISPOSTA FINALE a tutte le sciocchezze legate alla tastiera per le quali Apple non ha mai fornito una soluzione. Ora lo userò per tutti i miei progetti, vecchi e nuovi, e risparmierò tempo e mal di testa che questa tastiera appare, scompare o non scompare, o come nasconderlo, e perché si sovrappone, i problemi mi hanno causato dal giorno che sto programmando per iPhone.
Zeeshan,

1
Avevo scritto il mio codice per spostare il campo di testo, proprio come le altre soluzioni qui. Ho scoperto che IQKeyboardManager è molto buono e lo incorporerò d'ora in poi. Terrò il mio codice a portata di mano nel caso in cui il framework non sia aggiornato.
TM Lynch,

1
Questa risposta deve essere più alta, molto più alta.
JC

15

Per errore schermo nero (Swift 4 e 4.2) .

Ho risolto il problema dello schermo nero. Nella soluzione verificata L'altezza della tastiera cambia dopo aver toccato e ciò causa uno schermo nero.

Devi usare UIKeyboardFrameEndUserInfoKey invece di 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
    }
}

Non funzionerà se è presente una barra delle schede. Devi calcolare l'altezza della barra, altrimenti ci sarà uno spazio nero tra la tastiera e la vista.
Ankur Lahiry,

Questo non risolve l'area nera in cui la tastiera era su iPhone X e versioni successive. E ogni volta che la tastiera appare e scompare, la vista principale continua a scorrere verso il basso.
Edison,

14

Vedo che tutte le risposte stanno spostando la vista stessa dal valore dell'altezza della tastiera. Bene, ho una risposta elaborata, che potrebbe essere utile se stai usando i vincoli, ad esautolayout , ad , che sposta una vista modificando il valore del vincolo (vincoli inferiore o superiore, ad esempio) di un valore predefinito oppure è possibile utilizzare il valore della dimensione della tastiera.

In questo esempio, utilizzo il vincolo inferiore dal campo di testo alla Vista layout inferiore con un valore iniziale di 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()
    }
}

Salve signore, potrebbe dirmi perché non funziona se posizionato in una vista che contiene anche un TableView? Funziona bene nello stesso scenario quando contiene CollectionView.
elarcoiris,

9

Ci sono stati alcuni cambiamenti nel modo in cui definiamo KeyboardWillHideNotification.

Questa soluzione funziona con 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
cosa succede se il mio textField è in cima alla vista ..? intendo se esiste un campo di testo con origine Y = 0 .. ?? poi textField sta salendo e non riesco a vederlo
Saifan Nadaf,

7

Swift 5.0:

Dopo 4-5 ore di combattimento sono arrivato con una semplice estensione di UIViewController con un semplice codice che funziona come un fascino

* La vista non dovrebbe spostarsi quando TextField si trova sopra la tastiera

* Non è necessario impostare il valore costante su NSLayoutConstraint

* Nessuna libreria di terze parti richiesta

* Nessun codice di animazione richiesto

* Funziona anche su tableview

* Funziona con layout automatico / ridimensionamento automatico

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

Aggiungi questa estensione di UIResponder per ottenere quale TextField è selezionato

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

Quindi utilizzalo in qualsiasi ViewController

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

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

  • Registrare questa notifica in func viewWillAppear(_ animated: Bool)

  • Annullare la registrazione in func viewWillDisappear(_ animated:Bool)

    Scarica la demo qui


Sembrava la soluzione migliore, tuttavia ci sono un paio di bug. 1, il campo di testo si sposta verso l'alto ma quando inizio a digitarlo salta un po 'di più. 2, In orizzontale quando si digita textField a volte salta a sinistra.
Darren,

@Darren sto cercando di capire questi bug ma non li ho trovati, puoi dirmi dove hai preso questi bug, intendo per quale versione / dispositivo ... ??
Saifan Nadaf,

6

Per Swift 3, ho creato una sottoclasse UIViewController poiché avevo bisogno di un comportamento costante in tutti i controller di visualizzazione.

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

Ispirato dalla soluzione di Pavle, l'ho aggiornato per alzare automaticamente la tastiera di una certa percentuale dello spazio disponibile rimanente e anche trovare il campo focalizzato ricorsivamente per un corretto layout. Prendilo
Noor Dawod

Anche la mia barra delle schede si sta spostando verso l'alto con la finestra! :(
Alfi il

6

La risposta convalidata non tiene conto della posizione del campo di testo e presenta alcuni bug (doppio spostamento, non tornare mai alla posizione principale, spostamento anche se il campo di testo è in cima alla vista ...)

L'idea è:

  • per mettere a fuoco TextField posizione Y assoluta
  • per ottenere l'altezza della tastiera
  • per ottenere ScreenHeight
  • Quindi calcola la distanza tra la posizione della tastiera e il campo di testo (se <0 -> sposta in alto la vista)
  • usare UIView.transform invece di UIView.frame.origin.y - = .., perché è più facile tornare alla posizione originale con UIView.transform = .identity

allora saremo in grado di spostare la vista solo se necessario e dello spostamento specifico per avere il texField focalizzato appena sopra la tastiera

Ecco il codice:

Swift 4

class ViewController: UIViewController, UITextFieldDelegate {

var textFieldRealYPosition: CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

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

  // Delegate all textfields

}


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


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


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

}


Molto bene! (In viewDidLoad hai "VehiculeViewController" invece di "ViewController").
rene

Una risposta molto più completa e utile. Grazie! Suggerisco che il controllo della tastiera sia chiamato come segue perché fornirà una dimensione coerente della tastiera ......... se consenti keyboardSize = (notification.userInfo? [UIResponder.keyboardFrameEndUserInfoKey] come? NSValue) ?. cgRectValue .size
Ben

4

Ho notato che le altre risposte riguardavano il taglio della parte superiore della vista. Se vuoi semplicemente ridimensionare la vista senza tagliare alcun contenuto, prova questo metodo :)

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

I miei due centesimi per i principianti: nei campioni sopra qualcuno cambia le coordinate, altri usa la "maschera di ridimensionamento automatico" e altri vincoli:

Come dice Apple, non mescolare questi 3 tipi di logica. Se hai vincoli nello Storyboard, non provare a cambiare x / y. Non funziona definitivamente.


4

Quindi nessuna delle altre risposte sembra aver capito bene.

La buona tastiera comportamentale su iOS dovrebbe:

  • Ridimensiona automaticamente quando la tastiera cambia dimensioni (SÌ PU CAN)
  • Animare alla stessa velocità della tastiera
  • Animare usando la stessa curva della tastiera
  • Rispettare le aree sicure, se pertinenti.
  • Funziona anche su iPad / modalità Undocked

Il mio codice usa un NSLayoutConstraintdichiarato come@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

Potresti anche usare le trasformazioni, visualizzare gli offset, .... Penso che sia più facile con il vincolo. Funziona impostando un vincolo in basso, potrebbe essere necessario modificare il codice se la costante non è 0 / Non in basso.

Ecco il codice:

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

la sua risposta perfetta al 100% per tutti gli aggiornamenti di Guy Tableview Height quando si apre la tastiera

Per Swift4.2

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

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

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

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

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

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

Swift3.2

    override func viewDidLoad() {
          super.viewDidLoad()

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

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

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

       }
    }

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

Questa è la risposta migliore tbl dovrebbe essere tableView e ho aggiunto un po 'di riempimento: contentInset.bottom = keyboardFrame.size.height + 10
iphaaw

2

Per 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

Swift 4:

Stavo riscontrando un problema con la risposta più accettata, in cui nascondere la tastiera non riportava la vista fino in fondo alla pagina (solo parzialmente). Questo ha funzionato per me (+ aggiornato per 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
        }
    }
}

cosa succede se il mio textField è in cima alla vista ..? intendo se esiste un campo di testo con origine Y = 0 .. ?? poi textField sta salendo e non riesco a vederlo
Saifan Nadaf,

2

Simile alla risposta di @Boris, ma in 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

Ecco la mia soluzione (in realtà questo codice è per il caso quando hai pochi campi di testo nella tua vista, questo funziona anche per il caso quando hai un campo di testo)

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

Non dimenticare di impostare il delegato sui
campi di testo

Cambia la condizione in tastiera mostrandoti come, se (! CGRectContainsPoint (aRect, newOrgin!) &&! Self.viewWasMoved)
KingofBliss

aggiungi self.viewWasMoved = false quando ripristini il frame
KingofBliss

1

Aggiornato per Swift 3 ...

Come altri hanno già detto, è necessario aggiungere osservatori di notifica nel metodo viewDidLoad () del controller, in questo modo:

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

Ricorda di rimuovere i tuoi osservatori dove appropriato (lo faccio nel metodo 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)

Quindi, implementa i tuoi metodi show e hide - nota la linea che dice all'app di ignorare gli eventi di interazione (beginIgnoringInteractionEvents). Questo è importante poiché senza di esso, l'utente potrebbe toccare un campo o persino una vista di scorrimento e causare lo spostamento di una seconda volta, causando un terribile errore dell'interfaccia utente. Ignorare gli eventi di interazione prima che la tastiera venga mostrata e nascosta impedirà questo:

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

Infine, riattiva le interazioni dell'utente (ricorda, questo metodo si attiva dopo che la tastiera ha mostrato o salvato):

func enableUserInteraction()
    {
    UIApplication.shared.endIgnoringInteractionEvents()
    }

1

Codice 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

Se hai 2 o più campi di testo sullo stesso VC e l'utente tocca uno di essi e quindi tocca l'altro, senza chiamare la funzione tastieraWillHide, la vista salirà un'altra volta, il che non è necessario, perché avrai la tastiera, uno spazio vuoto che ha l'altezza della tastiera e quindi la vista, usando il codice nella risposta che ho modificato:

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

Per risolvere questo problema, sostituisci le due funzioni "KeyboardWillShow / Hide" con queste:

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

cosa succede se il mio textField è in cima alla vista ..? intendo se esiste un campo di testo con origine Y = 0 .. ?? poi textField sta salendo e non riesco a vederlo
Saifan Nadaf,

1

La soluzione di @ Boris è MOLTO buona ma la vista a volte può essere corrotta.

Per un allineamento perfetto, utilizzare il codice seguente

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

funzioni:

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

E,

@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

questo video tutorial è il migliore. 7 minuti e avrà molto senso. Una soluzione così semplice per quando hai più campi di testo e desideri che la vista di scorrimento sposti una quantità di "x" pixel quando viene toccato quel campo di testo specifico.

https://youtu.be/VuiPGJOEBH4

Solo questi passaggi:

-Posiziona tutti i campi di testo in una vista di scorrimento che è vincolata ai bordi della vista.

-Collegare tutti i campi di testo e scorrere la vista come delegati al controller della vista.

-Collegare tutti i campi di testo e scorrere la vista con un IBOutlet.

class ViewController: UIViewController, UITextFieldDelegate {

-Aggiungi il protocollo UITextFieldDelegate alla tua classe

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

-Aggiungi i metodi UITextFieldDelegate al tuo file rapido:

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

Il primo metodo attiva semplicemente il pulsante di ritorno sulla tastiera per chiudere la tastiera. Il secondo è quando si tocca qualsiasi campo di testo specifico, quindi si imposta l'offset y di quanto scorre la vista di scorrimento (il mio si basa sulla posizione y sui miei controller di vista 25,57,112,142). L'ultimo dice che quando tocchi via dalla tastiera la vista di scorrimento ritorna nella posizione originale.

Ho reso il mio pixel di visualizzazione perfetto in questo modo!


0

Questa funzionalità è stata creata in Ios, tuttavia dobbiamo farlo esternamente.
Inserisci il codice seguente
* Per spostare la vista quando textField è sotto la tastiera,
* Non spostare la vista quando textField è sopra la tastiera
* Per spostare la vista in base all'altezza della tastiera quando necessario.
Funziona e testato in tutti i casi.

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

| :: | A volte Vista verrà abbassata, in tal caso utilizzare l'altezza +/- 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
}

deve essere più stabile


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

Utilizzare il seguente codice per visualizzare Su su UITextField Clicked

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

Ho creato un cocoapod per semplificare la questione:

https://github.com/xtrinch/KeyboardLayoutHelper

Come usarlo:

Crea un vincolo inferiore del layout automatico, assegnagli una classe di KeyboardLayoutConstraint nel modulo KeyboardLayoutHelper e il pod farà il lavoro necessario per aumentarlo per adattarsi alla tastiera che appare e scompare. Vedi il progetto di esempio sugli esempi su come usarlo (ne ho fatti due: campi di testo all'interno di scrollView e campi di testo centrati verticalmente con due viste di base - accedi e registrati).

Il vincolo di layout inferiore può essere la vista contenitore, il campo di testo stesso, qualsiasi cosa, tu lo chiami.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.