Mover vista con teclado usando Swift

278

Tengo una aplicación que tiene un campo de texto en la mitad inferior de la vista. Esto significa que cuando voy a escribir en el campo de texto, el teclado cubre el campo de texto.

¿Cómo haría para mover la vista hacia arriba mientras escribo para poder ver lo que estoy escribiendo y luego volver a bajarlo a su lugar original cuando el teclado desaparece?

He buscado en todas partes, pero todas las soluciones parecen estar en Obj-C, que todavía no puedo convertir.

Cualquier ayuda sería muy apreciada.

Alex Catchpole
fuente
La mejor manera de hacer esto es colocar su contenido dentro de UIScrollView , luego ajustar la propiedad contentInset de la vista de desplazamiento por la altura del teclado cuando se muestra. Absolutamente no asuma la altura del teclado: use el valor de la notificación "teclado mostrará".
nielsbot
1
De hecho, los documentos de Apple le indican cómo hacerlo, en "Administración del teclado": developer.apple.com/library/ios/documentation/StringsTextFonts/…
nielsbot
11
Creo que todas las respuestas a continuación no tienen en cuenta un caso: ¿qué sucede si tiene varios campos de texto y algunos de ellos se encuentran en la parte superior de la pantalla? En cualquier momento el usuario que se nutre campo de texto, que sube más allá de la pantalla, estoy bastante seguro de la respuesta correcta debería detectar siit is actually needed to scroll view up when keyboard appears
theDC
Esta respuesta puede detectar si realmente es necesario desplazar la vista hacia arriba cuando aparece el teclado al verificar si el campo de texto que se está editando actualmente ocupa el mismo espacio que el teclado: stackoverflow.com/a/28813720/6749410
HirdayGupta

Respuestas:

710

Aquí hay una solución, sin manejar el cambio de un campo de texto a otro:

 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
}

Para resolver esto, reemplace las dos funciones keyboardWillShow/Hidecon estas:

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

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

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

EDITAR PARA 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
    }
}
Boris
fuente
56
Si el usuario toca otro campo de texto mientras el teclado está presente, la vista se empujará más hacia arriba, lo que provocará un área negra (el tamaño del teclado). Necesitamos solucionarlo teniendo una variable que rastree si el teclado está presente o no. . por ejemplo, si keyboardPresent == verdadero, no mueva el origen de la vista, etc., etc.
jonprasetyo
3
@Matthew Lin usa un booleano para que las funciones keyboardWillShow y hide solo funcionen una vez
iluvatar_GR
11
Solo una sugerencia, para que no tenga que depurar mucho como lo hice yo. Si tiene varios campos uitext en la misma pantalla, el tamaño del teclado puede variar (no muestra sugerencias para algunas entradas según su configuración), por lo que es recomendable configurar self.view.frame.origin.y = 0, siempre descartas el teclado. Por ejemplo, mostraría sugerencias para el campo de texto de su correo electrónico, por lo que el tamaño del teclado aumentaría y no mostrará sugerencias para el campo de contraseña, por lo que el tamaño del teclado disminuirá.
Vandan Patel
36
Debe usar en UIKeyboardFrameEndUserInfoKeylugar de UIKeyboardFrameBeginUserInfoKeyobtener el tamaño del teclado. No estoy seguro de por qué en este momento, pero el primero arrojará resultados más consistentes.
jshapy8
3
Por favor reemplace UIKeyboardFrameBeginUserInfoKeycon UIKeyboardFrameEndUserInfoKey. El primero da el cuadro inicial del teclado, que a veces viene cero, mientras que el segundo da el cuadro final del teclado.
Arnab
90

La forma más fácil que ni siquiera requiere ningún código:

  1. Descargue KeyboardLayoutConstraint.swift y agregue (arrastre y suelte) el archivo en su proyecto, si aún no está utilizando el marco de animación Spring.
  2. En su guión gráfico, cree una restricción inferior para la vista o el campo de texto, seleccione la restricción (haga doble clic en ella) y en el Inspector de identidad, cambie su clase de NSLayoutConstraint a KeyboardLayoutConstraint.
  3. ¡Hecho!

El objeto se moverá automáticamente hacia arriba con el teclado, en sincronización.

gammachill
fuente
44
Para seleccionar la restricción inferior, también puede ir al Inspector de tamaño, luego hacer doble clic en la restricción en la lista: raywenderlich.com/wp-content/uploads/2015/09/…
gammachill
3
Esto funcionó perfecto para mí. Es literalmente un proceso de 2 pasos. 1. Agregue KeyboardLayoutConstraint.swift, 2. En el guión gráfico, cree una restricción inferior para la vista o el campo de texto. NOTA: eliminé mis restricciones y agregué solo 1 restricción al final de la vista o campo de texto y cambié su clase de NSLayoutConstraint a KeyboardLayoutConstraint. Luego, cualquier vista / campo de texto, etc. arriba acabo de conectar las restricciones de ese elemento al elemento con un solo KeyboardLayoutConstraint y el resultado fue que todos los elementos a la vista se movieron ARRIBA / ABAJO cuando aparece / desaparece el teclado
Brian
44
Esta es la mejor solución, el código proporcionado no codifica ningún valor, como la longitud o la curva de la animación, o el tamaño del teclado. También es fácil de entender.
miguelSantirso
3
Esto funciona para mí, pero obtengo un espacio adicional de 50 px entre la parte superior del teclado y la parte inferior de mi scrollView. Me pregunto si se debe a la restricción inferior del Área segura que estoy usando. ¿Alguien se topó con esto?
Clifton Labrum
1
Esta fue una respuesta increíble. Muy buen diseño también. Una sugerencia: si sus vistas de texto / campos de texto están en las celdas de la vista de tabla, es posible que observe que las vistas que tienen esta restricción saltarán de manera incómoda cada vez que el usuario haga clic en ingresar y vaya al siguiente campo de texto. Puedes envolver las animaciones DispatchQueue.main.async {}para arreglarlo. ¡Buen trabajo! ¡Pulgares hacia arriba!
ScottyBlades
68

Una de las respuestas populares en este hilo usa el siguiente código:

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

Hay un problema obvio al compensar su vista por una cantidad estática. Se verá bien en un dispositivo pero se verá mal en cualquier configuración de otro tamaño. Deberá obtener la altura del teclado y usarlo como su valor de desplazamiento.

Aquí hay una solución que funciona en todos los dispositivos y maneja el caso extremo donde el usuario oculta el campo de texto predictivo mientras escribe.

Solución

Es importante tener en cuenta a continuación, estamos pasando self.view.window como nuestro parámetro de objeto. Esto nos proporcionará datos de nuestro teclado, como su altura.

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

Haremos que se vea bien en todos los dispositivos y manejaremos el caso en el que el usuario agrega o elimina el campo de texto predictivo.

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

Eliminar observadores

No olvide eliminar a sus observadores antes de abandonar la vista para evitar que se transmitan mensajes innecesarios.

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

Actualización basada en la pregunta de los comentarios:

Si tiene dos o más campos de texto, puede verificar si su view.frame.origin.y está en cero.

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)
}
Dan Beaulieu
fuente
1
cuando se trata con múltiples campos de texto, la vista sigue subiendo y no vuelve a bajar
Mugunthan Balakrishnan
Tendrá que cambiar sus condiciones para tener en cuenta los campos de texto
Dan Beaulieu
gracias por la respuesta, encontré la respuesta que estaba buscando en este hilo en desbordamiento de pila stackoverflow.com/questions/1126726/…
Mugunthan Balakrishnan
@MugunthanBalakrishnan gracias por mencionar esto, he agregado una solución.
Dan Beaulieu
Hola chicos, hay un error. Los observadores no se eliminan de la vista después de ser llamados en viewWillDisappear. Reemplace esta línea "NSNotificationCenter.defaultCenter (). RemoveObserver (self, name: UIKeyboardWillHideNotification, object: self.view.window)" con "NSNotificationCenter.defaultCenter (). RemoveObserver (self, name: UIKeyboardWillHideNotification, object: nil)" y luego observador se elimina
rudald
29

Agregue esto a su controlador de vista. Funciona de maravilla. Solo ajusta los valores.

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
}
usuario3677173
fuente
Esto funciona para mi. Sin embargo, es un poco desigual. ¿Cómo puedo hacer que esto suba sin problemas? También hay una manera de aplicarlo solo a uno de los campos de texto, ya que actualmente lo hace para todos. :(
DannieCoderBoi
2
Es posible que no funcione con "Diseño automático", por lo tanto, considere desactivarlo.
Teodor Ciuraru
1
Causa un comportamiento funky con autolayout @Josh, estás equivocado
Mike
55
¡No hagas esto! No puede asumir que el teclado es de cierto tamaño.
nielsbot
2
Debería usar keyboardSize. ¿Qué sucede cuando tiene vistas de accesorios y diferentes alturas de teclado en los dispositivos? Teclado separado?
xtrinch
25

Mejoré un poco una de las respuestas para que funcione con diferentes teclados y diferentes vistas / campos de texto en una página:

Añadir observadores:

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

Eliminar observadores:

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

    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
scipianne
fuente
3
Esta solución funciona mejor que la respuesta aceptada. La respuesta aceptada muestra el teclado solo una vez, lo que para mí es un error :)
Masih
Esto funciona para Xcode 10.1 y iOS 12. La respuesta aceptada ya no es válida.
zeeshan
Esta es una excelente respuesta, lo único que agregaría es realizar un seguimiento del área segura inferior en los dispositivos más nuevos (X, XS, etc.) para que tenga en cuenta eso.
Munib
@Munib Consulte stackoverflow.com/a/54993623/1485230 Otros problemas incluyen que la vista no se anima y el cambio de altura del teclado no se sigue.
Antzi
¿Qué pasa si mi textField está en la parte superior de la vista? quiero decir si hay un campo de texto con origen Y = 0 .. ?? entonces textField está subiendo y no puedo verlo
Saifan Nadaf
19

No es un anuncio o promoción o spam , solo una buena solución. Sé que esta pregunta tiene casi 30 respuestas y estoy tan sorprendido que nadie mencionó ni una sola vez sobre este hermoso proyecto de GitHub que lo hace todo por ti y aún mejor. Todas las respuestas solo mueven la vista hacia arriba. Acabo de resolver todos mis problemas con este IQKeyboardManager. Tiene más de 13000 estrellas.
Simplemente agregue esto en su podfile si está utilizando swift

pod 'IQKeyboardManagerSwift'

y luego dentro de su 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
    }
}

Agregue la línea IQKeyboardManager.shared.enable = truepara habilitarla.
Esta solución es imprescindible si va a la producción.

weegee
fuente
Esto es realmente bueno, pero la última versión no funciona para mí, he usado 6.2.1 e importo como import IQKeyboardManagery lo uso IQKeyboardManager.shared().isEnabled = trueen AppDelegate
Dhanu K
2
Y esto funciona de maravilla cuando se usan múltiples textos de edición. Esto me ahorró tiempo
Dhanu K
1
No puedo agradecer lo suficiente por señalar esta maravillosa biblioteca. Esta biblioteca es finalmente LA RESPUESTA FINAL a todas las tonterías relacionadas con el teclado para las que Apple nunca ha proporcionado una solución. Ahora lo usaré para todos mis proyectos, nuevos y antiguos, y ahorraré tiempo y dolor de cabeza que aparece, desaparece o no desaparece, o cómo ocultarlo, y por qué se superpone, los problemas me han estado causando desde día estoy programando para iPhones.
zeeshan
1
Había escrito mi propio código para mover el campo de texto, al igual que las otras soluciones aquí. Descubrí que IQKeyboardManager es muy bueno y lo incorporaré de ahora en adelante. Mantendré mi código a mano solo en caso de que el marco no esté actualizado.
TM Lynch
1
Esta respuesta debe ser más alta, mucho más alta.
JC
15

Para error de pantalla negra (Swift 4 y 4.2) .

Solucioné el problema de la pantalla en negro. En la solución verificada La altura del teclado cambia después de tocar y esto está causando una pantalla negra.

Tiene que usar UIKeyboardFrameEndUserInfoKey en lugar de 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
    }
}
Ali Ihsan URAL
fuente
No funcionará si hay una barra de pestañas. Debe calcular la altura de la barra de pestañas; de lo contrario, habrá un espacio negro en la pantalla entre el teclado y la vista.
Ankur Lahiry
Esto no repara el área negra donde estaba el teclado en el iPhone X y posteriores. Y cada vez que aparece y desaparece el teclado, la vista principal sigue deslizándose hacia abajo.
Edison
14

Veo que todas las respuestas están moviendo la vista en sí por el valor de la altura del teclado. Bueno, tengo una respuesta elaborada, que podría ser útil si está utilizando restricciones autolayout, es decir , que mueve una vista cambiando su valor de restricción (restricciones inferiores o superiores, por ejemplo) por un valor predefinido o puede usar el valor del tamaño del teclado.

En este ejemplo, uso la restricción inferior del campo de texto a la Vista de diseño inferior con un valor inicial de 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()
    }
}
Amro Shafie
fuente
Hola señor, ¿podría decirme por qué esto no funciona cuando se coloca en una vista que también contiene un TableView? Funciona bien en el mismo escenario cuando contiene un CollectionView.
elarcoiris
9

Ha habido algunos cambios en la forma en que definimos KeyboardWillHideNotification.

Esta solución funciona 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
    }
}
Ivan Le Hjelmeland
fuente
2
¿Qué pasa si mi textField está en la parte superior de la vista? quiero decir si hay un campo de texto con origen Y = 0 .. ?? entonces textField está subiendo y no puedo verlo
Saifan Nadaf
7

Swift 5.0:

Después de 4-5 horas de pelea, llegué con una extensión simple de UIViewController con un código simple que funciona como encanto

* La vista no debe moverse cuando TextField está sobre el teclado

* No es necesario establecer un valor constante en NSLayoutConstraint

* No se requiere biblioteca de terceros

* No se requiere código de animación

* Funciona en tableview también

* Esto funciona en diseño automático / cambio de tamaño automático

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

Agregue esta extensión de UIResponder para obtener qué TextField está seleccionado

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

Luego use esto en cualquier ViewController

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

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

  • Registre esta notificación en func viewWillAppear(_ animated: Bool)

  • Anular el registro de esta notificación en func viewWillDisappear(_ animated:Bool)

    Descargue la demostración aquí

Saifan Nadaf
fuente
Esta parecía la mejor solución, sin embargo, hay un par de errores. 1, el campo de texto se mueve hacia arriba, pero cuando empiezo a escribirlo, salta un poco más. 2, en horizontal al escribir el textField a veces salta a la izquierda.
Darren
@ Darren, estoy tratando de resolver estos errores, pero no los he encontrado, ¿podrías decirme de dónde sacaste estos errores? ¿Para qué versión / dispositivo ...?
Saifan Nadaf
6

Para Swift 3, hice una subclase UIViewController ya que necesitaba un comportamiento constante en todos los controladores de vista.

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)
  }
}
Pavle Mijatovic
fuente
Inspirado por la solución de Pavle, lo actualicé para elevar automáticamente el teclado en un cierto porcentaje del espacio disponible restante y también encontrar el campo enfocado de forma recursiva para un diseño adecuado. Consíguelo
Noor Dawod
¡Mi barra de pestañas también se está moviendo hacia arriba con la ventana! :(
Alfi
6

La respuesta validada no tiene en cuenta la posición del campo de texto y tiene algún error (desplazamiento doble, nunca vuelve a la posición primaria, desplazamiento incluso si el campo de texto está en la parte superior de la vista ...)

La idea es:

  • para obtener el foco TextField posición Y absoluta
  • para obtener la altura del teclado
  • para obtener el ScreenHeight
  • Luego calcule la distancia entre la posición del teclado y el campo de texto (si <0 -> sube la vista)
  • usar UIView.transform en lugar de UIView.frame.origin.y - = .., porque es más fácil volver a la posición original con UIView.transform = .identity

entonces podremos mover la vista solo si es necesario y del desplazamiento específico para tener el texField enfocado justo sobre el teclado

Aquí está el código:

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
}

}

Quentin N
fuente
¡Muy bien! (En viewDidLoad tiene "VehiculeViewController" en lugar de solo "ViewController").
René
Una respuesta mucho más completa y útil. ¡Gracias! Sugiero que la comprobación del teclado se llame de la siguiente manera porque dará un tamaño consistente del teclado ......... si permite keyboardSize = (notificación.usuarioInfo? [UIResponder.keyboardFrameEndUserInfoKey] como? NSValue) ?. cgRectValue .size
Ben
4

Noté que las otras respuestas involucraban cortar algo de la parte superior de la vista. Si simplemente desea cambiar el tamaño de la vista sin cortar ningún contenido, simplemente pruebe este método :)

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)
    }
}
Parque Grant
fuente
4

Mis dos centavos para principiantes: en las muestras anteriores, alguien cambia las coordenadas, otro usa la "máscara de autoresizing" y otras restricciones:

Como dice Apple, no mezcle estos 3 tipos de lógica. Si tiene restricciones en Storyboard, no intente cambiar x / y. Definitivamente no funciona.

ingconti
fuente
4

Entonces, ninguna de las otras respuestas parece acertar.

El teclado Good Behaviored en iOS debería:

  • Cambiar el tamaño automáticamente cuando el teclado cambia de tamaño (SÍ PUEDE)
  • Animar a la misma velocidad que el teclado
  • Animar usando la misma curva que el teclado
  • Respete las áreas seguras si es relevante.
  • Funciona también en iPad / modo desacoplado

Mi código usa un NSLayoutConstraintdeclarado como un@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

También podría usar transformaciones, ver compensaciones, ... Creo que es más fácil con la restricción aunque. Funciona al establecer una restricción en la parte inferior, es posible que deba modificar el código si su constante no es 0 / No en la parte inferior.

Aquí está el código:

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


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

su respuesta 100% perfecta para la altura de Tableview de actualización de todos cuando se abre el teclado

Para 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
         }
    }
Maulik Patel
fuente
Esta es la mejor respuesta. tbl debería ser tableView y agregué algo de relleno: contentInset.bottom = keyboardFrame.size.height + 10
iphaaw
2

Para 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()
}
Celil Bozkurt
fuente
2

Swift 4:

Estaba teniendo un problema con la respuesta más aceptada, en la que ocultar el teclado no devolvía la vista hasta el final de la página (solo parcialmente). Esto funcionó para mí (+ actualizado para Swift 4).

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

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

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0{
            self.view.frame.origin.y = 0
        }
    }
}
Rbar
fuente
¿Qué pasa si mi textField está en la parte superior de la vista? quiero decir si hay un campo de texto con origen Y = 0 .. ?? entonces textField está subiendo y no puedo verlo
Saifan Nadaf
2

Similar a la respuesta de @Boris, pero en 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
    }
}
Jerry Chong
fuente
1

Aquí está mi solución (en realidad, este código es para el caso cuando tiene pocos campos de texto en su vista, esto también funciona para el caso cuando tiene un campo de texto)

class MyViewController: UIViewController, UITextFieldDelegate {

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

var activeTextField: UITextField!
var viewWasMoved: Bool = false


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

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

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

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

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


func keyboardWillShow(notification: NSNotification) {

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

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

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

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

func keyboardWillHide(notification: NSNotification) {
    if (self.viewWasMoved) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}
Vah.Sah
fuente
No se olvide de configurar el delegado en los campos de texto
SwingerDinger
Cambie la condición en el teclado como si (! CGRectContainsPoint (aRect, newOrgin!) &&! Self.viewWasMoved)
KingofBliss
agregar self.viewWasMoved = false al restablecer el marco
KingofBliss
1

Actualizado para Swift 3 ...

Como han dicho otros, debe agregar observadores de notificación en el método viewDidLoad () de su controlador, de esta manera:

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

Recuerde eliminar a sus observadores cuando corresponda (lo hago en el método 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)

Luego, implemente sus métodos de mostrar y ocultar: observe la línea que le dice a la aplicación que ignore los eventos de interacción (beginIgnoringInteractionEvents). Esto es importante ya que sin él, el usuario podría tocar un campo o incluso una vista de desplazamiento y hacer que el cambio ocurra por segunda vez, lo que da como resultado un terrible error de la interfaz de usuario. Ignorar los eventos de interacción antes de que el teclado se muestre y se oculte evitará esto:

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

Por último, vuelva a habilitar las interacciones del usuario (recuerde, este método se activa después de que el teclado hizo Mostrar o Esconder):

func enableUserInteraction()
    {
    UIApplication.shared.endIgnoringInteractionEvents()
    }
Gene Loparco
fuente
1

Código 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
}
Rohit Sharma
fuente
1

Si tiene 2 o más campos de texto en el mismo VC, y el usuario toca uno de ellos y luego toca el otro, sin llamar a la función keyboardWillHide, la vista va hacia arriba una vez más, lo cual no es necesario, porque tendrás el teclado, un espacio en blanco que tiene la altura del teclado, y luego la vista, usando el código en la respuesta que edité:

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

Para resolver esto, reemplace las dos funciones "KeyboardWillShow / Hide" por estas:

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
        }
    }
}
Sr. Xcoder
fuente
¿Qué pasa si mi textField está en la parte superior de la vista? quiero decir si hay un campo de texto con origen Y = 0 .. ?? entonces textField está subiendo y no puedo verlo
Saifan Nadaf
1

La solución de @ Boris es MUY buena, pero la vista a veces puede corromperse.

Para la alineación perfecta, use el siguiente código

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

Funciones:

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

Y,

@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 
    }
} }
Eray Alparslan
fuente
0

Este video tutorial es el mejor. 7 minutos de duración y tendrá mucho sentido. Una solución tan simple para cuando tiene múltiples campos de texto y desea que la vista de desplazamiento mueva la cantidad "x" de píxeles cuando se toca ese campo de texto específico.

https://youtu.be/VuiPGJOEBH4

Solo estos pasos:

-Coloque todos sus campos de texto dentro de una vista de desplazamiento que esté restringida a los bordes de la vista.

-Conecte todos los campos de texto y vista de desplazamiento como delegados al controlador de vista.

-Conecte todos los campos de texto y vista de desplazamiento con un IBOutlet.

class ViewController: UIViewController, UITextFieldDelegate {

-Agregue el protocolo UITextFieldDelegate a su clase

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

-Agregue métodos UITextFieldDelegate a su archivo swift:

func textFieldShouldReturn(textField: UITextField) -> Bool {

    textField.resignFirstResponder()
    return true
}


func textFieldDidBeginEditing(textField: UITextField) {

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

func textFieldDidEndEditing(textField: UITextField) {

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

El primer método simplemente activa el botón de retorno en el teclado para descartar el teclado. El segundo es cuando toca cualquier campo de texto específico y luego establece el desplazamiento y de qué tan lejos se desplaza su vista de desplazamiento (la mía se basa en la ubicación y en mis controladores de vista 25,57,112,142). La última dice que cuando toca el teclado, la vista de desplazamiento vuelve a su ubicación original.

¡Hice mi píxel de vista perfecto de esta manera!

bme003
fuente
0

Esta característica shud se ha incorporado en iOS, sin embargo, debemos hacerlo externamente.
Inserte el código a continuación
* Para mover la vista cuando textField está debajo del teclado,
* No mover la vista cuando textField está arriba del teclado
* Para mover la vista según la altura del teclado cuando sea necesario.
Esto funciona y probado en todos los casos.

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 veces la vista estará abajo, en ese caso use la altura +/- 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)
Sujay UN
fuente
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
}

debe ser más estable

Hadevs Play
fuente
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)
 }
Himali Shah
fuente
0

Utilice el siguiente código para ver Up en 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()
}
Jugal K Balara
fuente
0

Hice un cocoapod para simplificar el asunto:

https://github.com/xtrinch/KeyboardLayoutHelper

Cómo usarlo:

Haga una restricción inferior de diseño automático, asígnele una clase de KeyboardLayoutConstraint en el módulo KeyboardLayoutHelper y el pod hará el trabajo necesario para aumentarlo para acomodar el teclado que aparece y desaparece. Vea el proyecto de ejemplo sobre ejemplos de cómo usarlo (hice dos: campos de texto dentro de una vista de desplazamiento y campos de texto centrados verticalmente con dos vistas básicas: inicio de sesión y registro).

La restricción de diseño inferior puede ser la vista de contenedor, el campo de texto en sí, cualquier cosa, lo que sea.

xtrinch
fuente