Un ejemplo rápido de vistas personalizadas para la input de datos (keyboard personalizado en la aplicación)

Gol

Quiero hacer un keyboard personalizado que solo se use dentro de mi aplicación, no un keyboard del sistema que deba instalarse.

Lo que he leído y probado

Documentación

  • Guía de progtwigción de la extensión de la aplicación: keyboard personalizado
  • Vistas personalizadas para la input de datos

El primer artículo anterior dice:

Asegúrese de que un keyboard personalizado de todo el sistema sea realmente lo que desea desarrollar. Para proporcionar un keyboard completamente personalizado solo para tu aplicación o para complementar el keyboard del sistema con teclas personalizadas en tu aplicación, el SDK de iOS ofrece otras opciones mejores. Lea acerca de las vistas de input personalizadas y las vistas accesorias de input en Vistas personalizadas para la input de datos en la Guía de progtwigción de text para iOS.

Eso es lo que me llevó al segundo artículo anterior. Sin embargo, ese artículo no tenía suficientes detalles para comenzar.

Tutoriales

  • iOS 8: crear un keyboard personalizado en Swift
  • Cómo hacer un keyboard personalizado en iOS 8 usando Swift
  • Tutorial Xcode 6: Teclado personalizado simple iOS 8.0 en Swift
  • Creación de un keyboard personalizado mediante la extensión de la aplicación iOS 8

Pude get un keyboard funcional del segundo tutorial en la list anterior. Sin embargo, no pude encontrar ningún tutorial que mostrara cómo hacer un keyboard solo en la aplicación como se describe en la documentation Vistas personalizadas para la input de datos .

Desbordamiento de stack

También pregunté (y respondí) estas preguntas en mi path para responder a la pregunta actual.

  • Cómo ingresar text usando los botones de un keyboard personalizado dentro de la aplicación.
  • Delegados en Swift

Pregunta

¿Alguien tiene un ejemplo mínimo (con incluso un button) de un keyboard personalizado en la aplicación? No estoy buscando un tutorial completo, solo una testing de concepto que puedo ampliar en mí mismo.

introduzca la descripción de la imagen aquí

Este es un keyboard básico en la aplicación. Se podría usar el mismo método para hacer casi cualquier layout de keyboard. Estas son las principales cosas que deben hacerse:

  • Cree el layout de keyboard en un file .xib, cuyo propietario es un file .swift que contiene una subclass UIView .
  • UITextField a UITextField que use el keyboard personalizado.
  • Use un delegado para comunicarse entre el keyboard y el controller de vista principal.

Cree el file de layout de keyboard .xib

  • En Xcode, vaya a Archivo> Nuevo> Archivo …> iOS> Interfaz de usuario> Ver para crear el file .xib.
  • Llamé a la mía Keyboard.xib
  • Agrega los botones que necesitas.
  • Utilice las restricciones de layout automático para que, independientemente del tamaño del keyboard, los botones cambiarán de tamaño en consecuencia.
  • Configure el propietario del file (no la vista raíz) para que sea el file Keyboard.swift. Esta es una fuente común de error. Mira la nota al final.

Cree el file de keyboard de subclass UIView de .swift

  • En Xcode, vaya a Archivo> Nuevo> Archivo …> iOS> Origen> Cocoa Touch Class para crear el file .swift.
  • Llamé a la mía Keyboard.swift
  • Agregue el código siguiente:

     import UIKit // The view controller will adopt this protocol (delegate) // and thus must contain the keyWasTapped method protocol KeyboardDelegate: class { func keyWasTapped(character: String) } class Keyboard: UIView { // This variable will be set as the view controller so that // the keyboard can send messages to the view controller. weak var delegate: KeyboardDelegate? // MARK:- keyboard initialization requinetworking init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initializeSubviews() } override init(frame: CGRect) { super.init(frame: frame) initializeSubviews() } func initializeSubviews() { let xibFileName = "Keyboard" // xib extention not included let view = NSBundle.mainBundle().loadNibNamed(xibFileName, owner: self, options: nil)[0] as! UIView self.addSubview(view) view.frame = self.bounds } // MARK:- Button actions from .xib file @IBAction func keyTapped(sender: UIButton) { // When a button is tapped, send that information to the // delegate (ie, the view controller) self.delegate?.keyWasTapped(character: sender.titleLabel!.text!) // could alternatively send a tag value } } 
  • Controle el arrastre desde los botones en el file @IBAction método @IBAction en el file .swift para enlazarlos a todos.

  • Tenga en count que el protocolo y el código de delegado. Vea esta respuesta para una explicación simple sobre cómo funcionan los delegates.

Configurar el controller de vista

  • Agregue un UITextField a su storyboard principal y conéctelo a su controller de vista con un IBOutlet . Llámalo campo de textField .
  • Utilice el siguiente código para el controller de vista:

     import UIKit class ViewController: UIViewController, KeyboardDelegate { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() // initialize custom keyboard let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 300)) keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped // replace system keyboard with custom keyboard textField.inputView = keyboardView } // requinetworking method for keyboard delegate protocol func keyWasTapped(character: String) { textField.insertText(character) } } 
  • Tenga en count que el controller de vista adopta el protocolo KeyboardDelegate que definimos anteriormente.

Error común

Si está obteniendo un error EXC_BAD_ACCESS, probablemente se deba a que configura la class personalizada de la vista como Keyboard.swift en lugar de hacerlo por el propietario del file nib.

Seleccione Keyboard.nib y luego elija Owner del file.

introduzca la descripción de la imagen aquí

Asegúrese de que la class personalizada para la vista raíz esté en blanco.

introduzca la descripción de la imagen aquí

Sobre la base de la respuesta de Suragch, necesitaba un button hecho y retroceso y si eres un novato como yo heres algunos errores que puedas encontrar y la forma en que los resolví.

¿Obtiene errores EXC_BAD_ACCESS? Yo incluí:

 @objc(classname) class classname: UIView{ } 

solucionó mi problema, sin embargo, la respuesta actualizada de Suragch parece resolver esto de la manera más apropiada / correcta.

¿Conseguir un error SIGABRT? Otra cosa tonta era arrastrar las conexiones de forma incorrecta, causando un error SIGABRT. No arrastre desde la function al button, sino el button a la function.

Agregar un button Hecho Agregué esto al protocolo en keyboard.swift:

 protocol KeyboardDelegate: class { func keyWasTapped(character: String) func keyDone() } 

Luego, conecté una nueva IBAction desde mi button hecho al keyboard. De esta manera salgo:

 @IBAction func Done(sender: UIButton) { self.delegate?.keyDone() } 

y luego salté de nuevo a mi viewController.swift donde estoy usando este keyboard y agregué este siguiente después de la tecla de functionWasTapped:

 func keyDone() { view.endEditing(true) } 

Adición de espacio de retroceso Esto me disparó mucho, porque debe configurar textField.delegate en el método viewDidLoad () (se muestra más adelante).

Primero: en keyboard.swift, agrega al protocolo func backspace ():

 protocol KeyboardDelegate: class { func keyWasTapped(character: String) func keyDone() func backspace() } 

Segundo: Conecte una nueva IBAction similar a la acción Done:

 @IBAction func backspace(sender: UIButton) { self.delegate?.backspace() } 

Tercero: Pase a viewController.swift donde aparece NumberPad.

Importante: en viewDidLoad (), configure todos los campos de text que usarán este keyboard. Entonces, su viewDidLoad () debería verse algo como esto:

  override func viewDidLoad() { super.viewDidLoad() self.myTextField1.delegate = self self.myTextField2.delegate = self // initialize custom keyboard let keyboardView = keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 240)) keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped // replace system keyboard with custom keyboard myTextField1.inputView = keyboardView myTextField2.inputView = keyboardView } 

No estoy seguro de cómo hacerlo, si hay una manera de hacerlo a todos los campos de text que están en la vista. Esto sería útil …

Forth: Still in viewController.swift necesitamos agregar una variable y dos funciones. Se verá así:

 var activeTextField = UITextField() func textFieldDidBeginEditing(textField: UITextField) { print("Setting Active Textfield") self.activeTextField = textField print("Active textField Set!") } func backspace() { print("backspaced!") activeTextField.deleteBackward() } 

Explicación de lo que está sucediendo aquí:

  1. Haces una variable que contenga un textField.
  2. Cuando se llama a "textFieldDidBeginEditing", establece la variable para que sepa con qué textField estamos tratando. Agregué muchas impresiones () así que sabemos que todo está siendo ejecutado.
  3. Nuestra function de retroceso revisa el textField con el que estamos tratando y usa .deleteBackward (). Esto elimina el carácter inmediato antes del cursor.

Y deberías estar en el negocio. Muchas gracias a Suragchs por ayudarme a que esto ocurra.