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í:
- Haces una variable que contendrá un campo de texto.
- 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.
- 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
- Guía de programación de extensiones de aplicaciones: teclado personalizado
- Vistas personalizadas para entrada de datos
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
- iOS 8: crear un teclado personalizado en Swift
- Cómo hacer un teclado personalizado en iOS 8 usando Swift
- Tutorial de Xcode 6: Teclado personalizado simple iOS 8.0 en Swift
- Crear un teclado personalizado con la extensión de aplicación iOS 8
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.
- Cómo ingresar texto usando los botones de un teclado personalizado en la aplicación
- Delegados en Swift
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 unIBOutlet
. LlámalotextField
. -
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.