Pregunta

Estoy haciendo un campo de entrada para palabras clave, y mientras los usuarios escriben, estoy mostrando sugerencias para palabras clave en una lista debajo de la posición de intercalación. El campo de entrada es una sola línea, por lo que estoy usando la tecla de flecha arriba / abajo para seleccionar una sugerencia y Enter para insertarla. Y está funcionando principalmente, con la gran excepción de que la tecla arriba / abajo también cambia la posición del cursor al principio / final del TextField .

He intentado utilizar preventDefault () y stopImmediatePropagation () en el detector de eventos KeyboardEvent.KEY_DOWN que también utilizo para cambiar el sugerencia seleccionada, pero eso no cambia nada. Verifiqué que la carret aún no se movió cuando se activó el evento KeyboardEvent.KEY_DOWN , pero visualmente puedo ver que se está moviendo antes de que se suelte la tecla (tecla arriba).

Podría guardar la posición de intercalación y luego restablecer el comportamiento predeterminado. Pero eso implicaría correctamente un código similar a un hack usando un temporizador.

Entonces, ¿alguien sabe cómo evitar el comportamiento predeterminado?

¿Fue útil?

Solución

No puedes evitarlo, pero puedes revertirlo. Para ello, agregue controladores con diferentes prioridades al mismo evento: KeyboardEvent.DOWN. Uno se ejecutará antes que TextField's, y guardará los índices de selección y el otro después de restaurarlos. El código de trabajo sigue:

    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import mx.controls.TextInput;
    import mx.events.FlexEvent;

    public class FooledTextInput extends TextInput
    {
        private var ssi : int = 0;
        private var sei : int = 0;

        public function FooledTextInput()
        {
            super();

            this.addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, false, 10000);
            this.addEventListener(KeyboardEvent.KEY_DOWN, onAfterKeyDown, false, -10000);
        }

        private function onBeforeKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                ssi = this.selectionBeginIndex;
                sei = this.selectionEndIndex;
            }   
        } 

        private function onAfterKeyDown(e : KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                this.setSelection(ssi, sei);
            }   
        } 
    }

Es posible que desee mejores nombres para ssi (índice de inicio de selección) y sei (índice de finalización de selección), era demasiado flojo para encontrar algunos. Creo que esta solución se basó en una publicación de Alex Harui, no lo recuerdo exactamente, pero tiene muchas cosas buenas relacionadas con Flex en su blog.

ACTUALIZACIÓN: Para la chispa TextInput, prevenir no solo es posible, es realmente fácil. Todo lo que necesita hacer es capturar el evento en la fase de captura y detener la propagación. Código:

package
{
    import flash.events.KeyboardEvent;
    import flash.ui.Keyboard;

    import spark.components.TextInput;

    public class HackedTextInput extends TextInput
    {
        public function HackedTextInput()
        {
            super();
            addEventListener(KeyboardEvent.KEY_DOWN, onBeforeKeyDown, true);
        }

        private function onBeforeKeyDown(e:KeyboardEvent) : void
        {
            if (e.keyCode == Keyboard.UP || e.keyCode == Keyboard.DOWN)
            {
                e.stopImmediatePropagation();
            }   
        }  
    }
}

Tenga en cuenta el último parámetro en la llamada addEventListener, que se establece en verdadero para que se llame al controlador en la fase de captura. Lamentablemente, esta solución no funciona para mx TextInput, solo para la chispa.

Otros consejos

He publicado una solución para este problema aquí:
AS3: setSelection Over Arrow Override

La solución de bug-a-lot es intrigante: no pensé en usar las prioridades. En cambio, hice uso de las diferentes fases del proceso del evento. El problema para mí fue decidir si las teclas de flecha deberían avanzar o retroceder un carácter dentro del campo de texto dado, o saltar al campo siguiente o anterior en el formulario.

Primero, anulo el manejo de eventos de la etapa para las teclas:

stage.addEventListener(KeyboardEvent.KEY_UP, typing);
// Sneak in before the normal processing handles right and left arrow keystrokes.
stage.addEventListener(KeyboardEvent.KEY_DOWN, pretyping, true, 10); 

Tenga en cuenta que procesaré cada tecla dos veces, antes de que el sistema haga su magia (se llama pretyping antes de KEY_DOWN) para que pueda ver dónde está el cursor antes de que Flash lo mueva, y después de que el sistema lo maneje (con mecanografía, llamado después de KEY_UP).

/** Capture prior state of text field so we can later tell if user should tab to next field or previous field. */
private function pretyping(evt:KeyboardEvent):void {
    var keyString:String = Configuration.getKeyString(evt);
    if (isFocusInTextBox()) {
        var tf:TextField = getFocus() as TextField;
        capturePhaseCaret = tf.caretIndex;
    }
}

getKeyString es un método mío; todo lo que hace es convertir esos códigos en mnemónicos convenientes. E isFocusInTextBox es una llamada a mi administrador de enfoque: reemplacé el administrador de enfoque estándar para superar otros problemas de Flash. Solo necesito saber si la cosa es un campo de texto o no.

Luego tengo que procesar la clave después de que Flash ya haya movido el cursor y tal vez incluso haya saltado a un nuevo campo, y al mirar el estado anterior, decida qué hizo Flash y lo deshaga y luego haga lo que debería suceder. Mi función '' escribiendo '' tiene muchas cosas que no se necesitan para esta discusión, pero lo importante es llamar a allowKeyMapping. allowKeyMapping decide si el usuario ingresó la flecha hacia adelante (o la flecha hacia abajo) desde la última posición del carácter en el campo de texto, o si ingresó la flecha hacia atrás desde el principio. Si es así, "escribiendo" irá al campo siguiente o al anterior, respectivamente.

    /** Prefer default behavior and do not allow certain kestrokes to be reinterpreted by key mappings, such as left and right cursor keys in text boxes. */
    private function allowKeyMapping(keyString:String) {
        var allow:Boolean;
        // If focus is in a text field, allow right arrow to advance to next field only if caret is at end of text.
        // Conversely, allow left arrow to back up to previous field only if caret is at beginning of text.
        // The trick is that the normal processing of keystrokes by TextFields occurs before this method is called,
        // so we need to know the caret position from before the key was pressed, which we have stored in capturePhaseCaret, set in pretyping.
        if (isDragging) {
            allow = false;
        }
        else if (isFocusInTextBox()) {
            var tf:TextField = getFocus() as TextField;
            if (keyString == Configuration.LEFT_CURSOR_KEY) {
                allow = tf.caretIndex == 0 && capturePhaseCaret == 0;
            }
            else if (keyString == Configuration.RIGHT_CURSOR_KEY) {
                allow = tf.caretIndex == tf.text.length && capturePhaseCaret == tf.text.length;
            }
            else {
                allow = true;
            }
        }
        else {
            allow = true;
        }
        return allow;
    }

Lo siento, no tengo un ejemplo compacto preparado. Simplemente pensé que era importante enfatizar que puedes evitar la inclinación de Flash por hacer las cosas por ti, ya sea que quieras que sucedan o no.

Podría haber algún efecto rápido con la solución de bug-a-lot.

Hay una solución de trabajo y un buen truco usando stage.invalidate () y el Event.RENDER de stage descrito aquí:

AS3: setSelection Up Arrow Override

Esta es mi solución para ese problema. Estoy seguro de que hay una mejor manera, pero probablemente requeriría extender el control TextInput.

private function onKeyDown(event:KeyboardEvent):void
{
    if(event.keyCode == flash.ui.Keyboard.UP)
    {
        var begin:int = textinput.selectionBeginIndex;
        var end:int = textinput.selectionEndIndex;
        textinput.setSelection(begin,end);
    }
}

No es sexy pero funciona.

por defecto los eventos son prioridad 0 en UIComponent para que siempre puedas dejar de evitar que algo suceda, aquí evitas todo KeyboardEvent.KEY_DOWN

yourObject.addEventListener(KeyboardEvent.KEY_DOWN, _preventDefault, false, 1, true );
private function _preventDefault(event:KeyboardEvent):void 
{
event.preventDefault();
event.stopImmediatePropagation();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top