Как предотвратить поведение стрелки вверх / вниз по умолчанию в TextField?

StackOverflow https://stackoverflow.com/questions/1018259

Вопрос

Я делаю поле ввода для ключевых слов, и пока пользователи пишут, я отображаю предложения для ключевых слов в списке под позицией каретки. Поле ввода - одна строка, поэтому я использую клавишу со стрелкой вверх / вниз, чтобы выбрать предложение, и Enter, чтобы вставить его. И это в основном работает, с большим исключением, что клавиша вверх / вниз также изменяет позицию каретки на начало / конец TextField .

Я попытался использовать protectDefault () и stopImmediatePropagation () в прослушивателе событий KeyboardEvent.KEY_DOWN , который я также использую для изменения выбрано предложение, но это ничего не меняет. Я проверил, что каретка еще не сдвинулась при возникновении события KeyboardEvent.KEY_DOWN , но визуально я вижу, что оно перемещается до отпускания клавиши (клавиша вверх).

Я мог бы просто сохранить позицию каретки, а затем сбросить стандартное поведение. Но это будет правильно включать в себя некоторый взломанный код с использованием таймера.

Так кто-нибудь знает, как предотвратить поведение по умолчанию?

Это было полезно?

Решение

Вы не можете предотвратить это, но вы можете изменить это. Для этого вы добавляете в обработчики с разными приоритетами одно и то же событие - KeyboardEvent.DOWN. Один будет выполняться до TextField и сохранять индексы выбора, а другой - после их восстановления. Рабочий код выглядит следующим образом:

    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);
            }   
        } 
    }

Возможно, вам потребуются более подходящие имена для ssi (начальный индекс выбора) и sei (конечный индекс выбора), мне было лень найти их. Я думаю, что это решение было основано на посте Алекса Харуи, я точно не помню, но у него есть много хороших вещей, связанных с Flex в его блоге.

ОБНОВЛЕНИЕ . Для искры TextInput предотвращение не только возможно, но и действительно легко. Все, что вам нужно сделать, это перехватить событие на этапе захвата и остановить распространение. Код:

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();
            }   
        }  
    }
}

Обратите внимание на последний параметр в вызове addEventListener, для которого установлено значение true, чтобы обработчик вызывался на этапе захвата. К сожалению, это решение не работает для mx TextInput, только для искрового.

Другие советы

Я разместил решение этой проблемы здесь:
AS3: setSelection Override Arrow Override

Решение по многим ошибкам интригует - я не думал использовать приоритеты. Вместо этого я использовал различные фазы процесса события. Для меня проблема заключалась в том, чтобы решить, должны ли клавиши со стрелками перемещаться вперед или отступать на один символ в данном текстовом поле, или переходить к следующему или предыдущему полю в форме.

Сначала я переопределяю обработку событий на этапе для ключей:

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); 

Обратите внимание, что я обработаю каждую клавишу дважды - до того, как система выполнит свое волшебство (предварительный набор вызывается перед KEY_DOWN), поэтому я могу видеть, где находится курсор, до того, как Flash переместит его, и после того, как система его обработает (набрав, после 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 - мой метод - все, что он делает, это превращает эти коды в удобную мнемонику. И isFocusInTextBox - это вызов моего менеджера фокуса - я заменил стандартный менеджер фокуса, чтобы преодолеть другие проблемы с Flash. Мне просто нужно знать, если это текстовое поле или нет.

Затем я должен обработать клавишу после того, как Flash уже переместил каретку и, возможно, даже перепрыгнул на новое поле, и, взглянув на предыдущее состояние, решить, что сделал Flash, отменить его и затем сделать то, что должно произойти. Моя функция "печатать" есть много вещей, которые не нужны для этого обсуждения, но важно сделать так, чтобы он вызывал allowKeyMapping. allowKeyMapping решает, ввел ли пользователь стрелку вперед (или стрелку вниз) из последней позиции символа в текстовом поле, или ввел стрелку назад с начала. Если это так, " введите " перейдет к следующему или предыдущему полю соответственно.

    /** 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;
    }

Извините, у меня нет подготовленного компактного примера. Я просто подумал, что важно подчеркнуть, что вы можете обойти склонность Flash к тому, чтобы делать что-то для вас, хотите ли вы, чтобы это произошло или нет.

В решении проблемы с ошибками может быть какой-то эффект флик.

Существует рабочее решение и хороший прием, использующий stage.invalidate () и Event.RENDER этапа, описанные здесь:

AS3: setSelection Override Arrow Override

Это мой способ решения этой проблемы. Я уверен, что есть лучший способ, но это, вероятно, потребует расширения элемента управления 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);
    }
}

Не сексуально, но это работает.

по умолчанию событие имеет приоритет 0 на UIComponent так что вы всегда можете остановить, остановить что-то случиться, здесь вы предотвращаете все KeyboardEvent.KEY_DOWN

yourObject.addEventListener(KeyboardEvent.KEY_DOWN, _preventDefault, false, 1, true );
private function _preventDefault(event:KeyboardEvent):void 
{
event.preventDefault();
event.stopImmediatePropagation();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top