guide - ¿Cómo se establece el orden de tabulación en iOS?
xcode constraints (8)
¿Hay alguna forma (ya sea en IB o en código) para establecer el orden de tabulación entre campos de texto en una vista?
Tenga en cuenta que no estoy hablando del siguiente campo de formulario después de presionar el botón de retorno (o "Siguiente"): muchos teclados bluetooth tienen una tecla de tabulación, que parece desplazarse por los campos en un orden completamente diferente. En mi caso particular, este orden no corresponde a la posición de los campos en la vista o incluso al orden en que se agregaron los campos. La modificación del archivo xib a mano para cambiar el NSNextKeyView tampoco parece marcar la diferencia.
¿Alguien sabe cómo cambiar esta orden?
Así es como configuras el orden de las pestañas en iOS:
El comportamiento de la tecla Tab en ios será el siguiente: - cuando presiona tab en el teclado externo - el control atraviesa todos los campos de texto en esa pantalla llamando solo al método shouldBeginEditing donde su valor de retorno también lo determina Apple, que no puede anularse. Después de escanear todos los campos, calcula el campo de texto x más cercano relativo para ver el desplazamiento desde el campo de texto actual y luego el campo Y Positioned más cercano.
Tampoco se puede hacer nada hasta que el control llegue al método textFieldDidBeginEditing.
La razón de la restricción de Apple podría ser permitirle a los desarrolladores que sigan las pautas de la interfaz de usuario donde el siguiente respondedor del campo debería ser su campo más cercano en lugar de cualquier otro campo.
Estoy interesado en resolver el mismo problema, aunque hasta ahora el orden predeterminado, que parece ser de izquierda a derecha, luego de arriba hacia abajo, es el que quiero.
Probé la hipótesis de que el cursor se mueve en primer orden a través del árbol de las subvistas y la supervista, pero eso no es cierto. Cambiar el orden de las subvistas sin cambiar su ubicación no cambió el orden de los campos recorridos por las pestañas .
Una característica posiblemente útil es que el método textFieldShouldBeginEditing del delegado del campo de texto parece ser invocado para cada campo de texto en la ventana de la aplicación. Si eso devuelve NO, entonces no se elegirá el campo de texto, por lo que si puede definir el orden deseado y hacer solo el correcto, devuelva SÍ, eso podría resolver su problema.
La única forma que he encontrado para detectar de manera única una pulsación de tecla Tab en un teclado físico, es implementar el método insertText: del protocolo UIKeyInput en un objeto personalizado que puede ser BecomeFirstResponder.
- (void)insertText:(NSString *)text {
NSLog(@"text is equal to tab character: %i", [text isEqualToString:@"/t"]);
}
No conseguí que esto funcionara mientras se subclasificaba UITextField, lamentablemente, ya que UITextField no permite que se llame al método insertText: protocol.
Podría ayudarte en el camino, sin embargo ..
La respuesta de @ sprocket solo fue de alguna utilidad. El hecho de que algo salga de la caja no significa que deba dejar de pensar en una mejor manera, o incluso en la forma correcta , de hacer algo. Como notó, el comportamiento no está documentado, pero se ajusta a nuestras necesidades la mayor parte del tiempo.
Sin embargo, esto no fue suficiente para mí. Piense en un lenguaje RTL y las pestañas seguirán tabulando de izquierda a derecha, sin mencionar que el comportamiento es completamente diferente de simulador a dispositivo (el dispositivo no enfoca la primera entrada en la pestaña). Sin embargo, lo más importante es que la implementación no documentada de Apple parece considerar solo las vistas instaladas actualmente en la jerarquía de vistas.
Piense en una forma en forma de (sin juego de palabras) una vista de tabla. Cada celda tiene un control único, por lo tanto, no todos los elementos de la forma pueden ser visibles al mismo tiempo. Apple simplemente retrocederá una vez que hayas alcanzado el último control (en la pantalla), en lugar de desplazarte hacia abajo. Este comportamiento definitivamente no es lo que deseamos.
Así que esto es lo que se me ocurrió. Su formulario debe ser administrado por un controlador de vista, y los controladores de vista son parte de la cadena de respuesta. Así que eres perfectamente libre de implementar los siguientes métodos:
#pragma mark - Key Commands
- (NSArray *)keyCommands
{
static NSArray *commands;
static dispatch_once_t once;
dispatch_once(&once, ^{
UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:@"/t" modifierFlags:0 action:@selector(tabForward:)];
UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:@"/t" modifierFlags:UIKeyModifierShift action:@selector(tabBackward:)];
commands = @[forward, backward];
});
return commands;
}
- (void)tabForward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.firstObject becomeFirstResponder];
}
- (void)tabBackward:(UIKeyCommand *)command
{
NSArray *const controls = self.controls;
UIResponder *firstResponder = nil;
for (UIResponder *const responder in controls.reverseObjectEnumerator) {
if (firstResponder != nil && responder.canBecomeFirstResponder) {
[responder becomeFirstResponder]; return;
}
else if (responder.isFirstResponder) {
firstResponder = responder;
}
}
[controls.lastObject becomeFirstResponder];
}
Se puede aplicar una lógica adicional para el desplazamiento de respondedores fuera de la pantalla visible de antemano.
Otra ventaja de este enfoque es que no es necesario que subclasses todos los tipos de controles que desee mostrar (como UITextField
s), pero en su lugar puede gestionar la lógica en el nivel de controlador, donde, seamos honestos, es el lugar adecuado para hacer asi que.
Lo resolví subclasificando UITextField como NextableTextField. Esa subclase tiene una propiedad de clase UITextField con IBOutlet una conexión.
Construye la interfaz en IB. Establezca la clase de su campo de texto en NextableTextField. Utilice las conexiones Inspector para arrastrar una conexión al campo ''siguiente'' al que desea tabular.
En su clase de delegado de campo de texto, agregue este método delegado ...
- (BOOL)textFieldShouldReturn:(UITextField *) textField
{
BOOL didResign = [textField resignFirstResponder];
if (!didResign) return NO;
if ([textField isKindOfClass:[NextableTextField class]])
dispatch_async(dispatch_get_current_queue(), ^{ [[(NextableTextField *)textField nextField] becomeFirstResponder]; });
return YES;
}
Por cierto, no se me ocurrió esto; solo recuerda ver la idea de otra persona.
Puede hacer esto configurando la etiqueta para cada campo de texto y manejándolo en el método textShouldReturn.
Vea este blogpost al respecto: http://iphoneincubator.com/blog/windows-views/how-to-create-a-data-entry-screen
Registre un UIKeyCommand para detectar la tecla de tabulación presionada. Hice esto en mi controlador de vista actual.
self.addKeyCommand(UIKeyCommand(input: "/t", modifierFlags: [], action: #selector(tabKeyPressed)))
Dentro de la pestaña keyKeyPressed handler, encuentre su campo activo actual y luego configure su próximo respondedor. orderedTextFields es una matriz de UITextField en el orden de tabulación que quiero.
func tabKeyPressed(){
let activeField = getActiveField()
if(activeField == nil){
return
}
let nextResponder = getNextTextField(activeField!)
nextResponder?.becomeFirstResponder()
}
func getActiveField() -> UITextField? {
for textField in orderedTextFields {
if(textField.isFirstResponder()){
return textField
}
}
return nil
}
func getNextTextField(current: UITextField) -> UITextField? {
let index = orderedTextField.indexOf(current)
if(orderedTextField.count-1 <= index!){
return nil
}
return orderedTextField[index! + 1]
}