ios swift keyboard custom-keyboard

ios - Un ejemplo rápido de vistas personalizadas para la entrada de datos(teclado personalizado en la aplicación)



swift keyboard (3)

Basándome en la respuesta de Suragch, necesitaba un botón de retroceso y hecho y si eres un novato como yo aquí hay algunos errores que podrías encontrar y la forma en que los resolví.

¿Recibe errores de 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 adecuada / correcta.

Obteniendo SIGABRT Error? Otra cosa tonta fue arrastrar las conexiones de la manera incorrecta, causando un error SIGABRT. No arrastre de la función al botón, sino el botón a la función.

Agregar un botón Listo Agregué esto al protocolo en keyboard.swift:

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

Luego conecté una nueva IBAction de mi botón hecho al teclado.

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

y luego volví a mi viewController.swift donde estoy usando este teclado y agregué lo siguiente después de la función keyWasTapped:

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

Agregar retroceso Esto me hizo tropezar mucho, porque debe establecer textField.delegate en self en el método viewDidLoad () (que se muestra más adelante).

Primero: en keyboard.swift, agregue 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 Hecho:

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

Tercero: a viewController.swift donde aparece el NumberPad.

Importante: en viewDidLoad () establece todos los TextFields que usarán este teclado. Entonces su viewDidLoad () debería verse así:

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 hacer esto en todos los TextFields que están en la vista. Esto sería útil ...

Adelante: todavía en 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 contendrá un campo de texto.
  2. Cuando se llama a "textFieldDidBeginEditing", establece la variable para que sepa con qué textField estamos tratando. He agregado muchas impresiones () para que sepamos que todo se está ejecutando.
  3. Nuestra función de retroceso luego verifica el textField con el que estamos tratando y utiliza .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 suceda.

Gol

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

Lo que he leído y probado

Documentación

El primer artículo anterior establece:

Asegúrese de que un teclado personalizado de todo el sistema es lo que desea desarrollar. Para proporcionar un teclado totalmente personalizado solo para su aplicación o para complementar el teclado del sistema con teclas personalizadas solo en su aplicación, el SDK de iOS proporciona otras opciones mejores. Lea sobre las vistas de entrada personalizadas y las vistas de accesorios de entrada en Vistas personalizadas para la entrada de datos en la Guía de programación de texto 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

Pude obtener un teclado funcional del segundo tutorial en la lista anterior. Sin embargo, no pude encontrar ningún tutorial que mostrara cómo hacer un teclado solo en la aplicación como se describe en las Vistas personalizadas para la documentación de Entrada de datos .

Desbordamiento de pila

También hice (y respondí) estas preguntas en mi camino a responder la pregunta actual.

Pregunta

¿Alguien tiene un ejemplo mínimo (con incluso un botón) de un teclado personalizado en la aplicación? No estoy buscando un tutorial completo, solo una prueba de concepto que pueda ampliar sobre mí mismo.


La clave es utilizar el protocolo UIKeyInput existente, al que UITextField ya se ajusta. Entonces, la vista del teclado solo necesita enviar insertText() y deleteBackward() al control.

El siguiente ejemplo crea un teclado numérico personalizado:

class DigitButton: UIButton { var digit: Int = 0 } class NumericKeyboard: UIView { weak var target: UIKeyInput? var numericButtons: [DigitButton] = (0...9).map { let button = DigitButton(type: .system) button.digit = $0 button.setTitle("/($0)", for: .normal) button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .largeTitle) button.setTitleColor(.black, for: .normal) button.layer.borderWidth = 0.5 button.layer.borderColor = UIColor.darkGray.cgColor button.accessibilityTraits = [.keyboardKey] button.addTarget(self, action: #selector(didTapDigitButton(_:)), for: .touchUpInside) return button } var deleteButton: UIButton = { let button = UIButton(type: .system) button.setTitle("⌫", for: .normal) button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .largeTitle) button.setTitleColor(.black, for: .normal) button.layer.borderWidth = 0.5 button.layer.borderColor = UIColor.darkGray.cgColor button.accessibilityTraits = [.keyboardKey] button.accessibilityLabel = "Delete" button.addTarget(self, action: #selector(didTapDeleteButton(_:)), for: .touchUpInside) return button }() init(target: UIKeyInput) { self.target = target super.init(frame: .zero) configure() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } // MARK: - Actions extension NumericKeyboard { @objc func didTapDigitButton(_ sender: DigitButton) { target?.insertText("/(sender.digit)") } @objc func didTapDeleteButton(_ sender: DigitButton) { target?.deleteBackward() } } // MARK: - Private initial configuration methods private extension NumericKeyboard { func configure() { autoresizingMask = [.flexibleWidth, .flexibleHeight] addButtons() } func addButtons() { let stackView = createStackView(axis: .vertical) stackView.frame = bounds stackView.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(stackView) for row in 0 ..< 3 { let subStackView = createStackView(axis: .horizontal) stackView.addArrangedSubview(subStackView) for column in 0 ..< 3 { subStackView.addArrangedSubview(numericButtons[row * 3 + column + 1]) } } let subStackView = createStackView(axis: .horizontal) stackView.addArrangedSubview(subStackView) let blank = UIView() blank.layer.borderWidth = 0.5 blank.layer.borderColor = UIColor.darkGray.cgColor subStackView.addArrangedSubview(blank) subStackView.addArrangedSubview(numericButtons[0]) subStackView.addArrangedSubview(deleteButton) } func createStackView(axis: NSLayoutConstraint.Axis) -> UIStackView { let stackView = UIStackView() stackView.axis = axis stackView.alignment = .fill stackView.distribution = .fillEqually return stackView } }

Entonces tú puedes:

textField.inputView = NumericKeyboard(target: textField)

Eso produce:

Lo anterior es bastante primitivo, pero ilustra la idea: UIKeyInput su propia vista de entrada y usar el protocolo UIKeyInput para comunicar la entrada del teclado al control.

También tenga en cuenta el uso de los accessibilityTraits de accessibilityTraits para obtener el comportamiento correcto de "Contenido hablado" »" Pantalla hablada ". Y si usa imágenes para sus botones, asegúrese de configurar accessibilityLabel también.


Este es un teclado básico en la aplicación. El mismo método podría usarse para hacer casi cualquier distribución de teclado. Estas son las principales cosas que deben hacerse:

  • Cree la distribución del teclado en un archivo .xib, cuyo propietario es un archivo .swift que contiene una subclase UIView .
  • Dígale al UITextField que use el teclado personalizado.
  • Use un delegado para comunicarse entre el teclado y el controlador de vista principal.

Cree el archivo de diseño de teclado .xib

  • En Xcode, vaya a Archivo> Nuevo> Archivo ...> iOS> Interfaz de usuario> Ver para crear el archivo .xib.
  • Llamé al mío Keyboard.xib
  • Agregue los botones que necesita.
  • Use restricciones de diseño automático para que, sin importar el tamaño del teclado, los botones cambien de tamaño según corresponda.
  • Configure el Propietario del archivo (no la vista raíz) para que sea el archivo Keyboard.swift. Esta es una fuente común de error. Ver la nota al final.

Cree el archivo de teclado de subclase .swift UIView

  • En Xcode, vaya a Archivo> Nuevo> Archivo ...> iOS> Fuente> Clase de Cocoa Touch para crear el archivo .swift.
  • Llamé al mío Keyboard.swift
  • Agregue el siguiente código:

    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 required 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 = Bundle.main.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 archivo @IBAction método @IBAction en el archivo .swift para conectarlos a todos.

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

Configurar el controlador de vista

  • Agregue un UITextField a su guión gráfico principal y conéctelo a su controlador de vista con un IBOutlet . Llámalo textField .
  • Use el siguiente código para el controlador 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 } // required method for keyboard delegate protocol func keyWasTapped(character: String) { textField.insertText(character) } }

  • Tenga en cuenta que el controlador de vista adopta el protocolo KeyboardDelegate que definimos anteriormente.

Error común

Si obtiene un error EXC_BAD_ACCESS, probablemente se deba a que configuró la clase personalizada de la vista como Keyboard.swift en lugar de hacerlo para el Propietario del archivo plumín.

Seleccione Keyboard.nib y luego elija Propietario del archivo.

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