Flex TextArea и TextInput на мобильном устройстве позиционируются неправильно

У меня возникли две проблемы при работе с TextArea и TextInput на мобильных компонентах, которые я не знаю, как решить. Во-первых, текст TextArea располагается неправильно, а во-вторых, он перекрывает другие компоненты.

Проблемы возникают, когда TextArea находится в Scroller (или программная клавиатура активируется и перемещает позицию TextArea).

В этом можно убедиться, добавив в мобильное приложение приведенный ниже код:

<s:Scroller width="100%" height="100%" top="100" bottom="100">
    <s:VGroup width="50%">
        <s:Button label="" height="600" width="440"/>
        <s:TextArea id="testing" />
        <s:TextArea id="testing2" />
        <s:Button label="" height="800" width="440"/>
    </s:VGroup>
</s:Scroller>

Первое изображение - это приложение с текстом.

введите описание изображения здесь

На втором изображении я немного прокрутил. Прокручивая вниз, я заметил, что текст остался на том же месте (он находится над кнопкой, которая была над ним)!

введите описание изображения здесь

CAVEAT:
Если я открою вид, текст сразу же будет размещен в правильном месте (в AIR Simulator) и снова будет правильно позиционирован, когда контент займет свое окончательное положение (на мобильных устройствах текст, кажется, исчезает до последнего упокоения). Это хорошая новость, поскольку что-то происходит при броске, чего не происходит при ручном нажатии, перетаскивании и отпускании (не броске) или при активации мягкой клавиатуры.

К сожалению, текст может по-прежнему отображаться поверх всего остального контента, игнорируя маску прокрутки, но я могу смириться с этим, если другая первая проблема будет исправлена.

ОБНОВЛЕНИЕ
Я могу изменить положение текста в правильном положении, если установлю ширину на ширину +1. Это не сработает, потому что я явно не хочу изменять его размер. Я попытался сделать его недействительным, но ничего не работает. Вот код, который я пробовал в событии softKeyboardActivating. Раскомментируйте ширину = ширина + 1, чтобы увидеть, как она "работает":

    <s:TextArea id="testing" softKeyboardActivate="testing_softKeyboardActivateHandler(event)"/>

<fx:Script>
    <![CDATA[
        import mx.core.IInvalidating;
        protected function testing_softKeyboardActivateHandler(event:SoftKeyboardEvent):void {
            trace("Activating");
            /*testing.invalidateProperties();
            testing.invalidateDisplayList();
            testing.invalidateSize();
            testing.validateNow();
            parentGroup.validateNow();
            scroller.validateNow();*/
            // testing.invalidateParentSizeAndDisplayList();
            //IInvalidating(testing.parent).invalidateSize();
            //IInvalidating(testing.parent).invalidateDisplayList();
            //testing.width = NaN;
            //testing.width = testing.width+1;
        }
    ]]>
</fx:Script>

ОБНОВЛЕНИЕ 2:
Этот код работает, но это взлом, и он намного медленнее, чем код, который скроллер использует при переходе в представление:

protected function testing_softKeyboardActivateHandler(event:SoftKeyboardEvent):void {
    StageTextAreaSkin2(testing.skin).styleChanged("styleName");
}

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

Это было протестировано с Flex 4.6, AIR 3.5 на Mac в AIR Simulator, iPhone 5 и Android Nexus 7.


person 1.21 gigawatts    schedule 19.01.2013    source источник


Ответы (2)


Это ошибка Flex, связанная с собственными текстовыми элементами управления. Если вы включите следующее в свое приложение верхнего уровня, это решит проблему:

<fx:Style>
        @namespace s "library://ns.adobe.com/flex/spark";
        @namespace mx "library://ns.adobe.com/flex/mx";
        @namespace local "*";
        s|TextInput {
            skinClass: ClassReference("spark.skins.mobile.TextInputSkin");
            showPromptWhenFocused:false;
        }
        s|TextArea {
            skinClass: ClassReference("spark.skins.mobile.TextAreaSkin");
        }
</fx:Style>
person Eduardo    schedule 21.01.2013

Вот обходной путь. Создайте файл MXML (обычно подойдет StageTextArea.mxml) и поместите в него этот код.

<?xml version="1.0" encoding="utf-8"?>
<s:TextArea xmlns:fx="http://ns.adobe.com/mxml/2009" 
            xmlns:s="library://ns.adobe.com/flex/spark"
            softKeyboardActivate="softKeyboardActivateHandler(event)"
            softKeyboardDeactivate="softKeyboardDeactivateHandler(event)"
            added="addedHandler(event)" 
            removed="removedHandler(event)">

    <!-- USAGE 
        <controls:StageTextArea id="myTextArea" parentScroller="{myScroller}"/>
    -->

    <fx:Script>
        <![CDATA[
            import mx.events.PropertyChangeEvent;

            import spark.components.Scroller;

            private var _parentScroller:Scroller;

            public function get parentScroller():Scroller {
                return _parentScroller;
            }

            /**
             * Adds a listener to an ancestor scroller. 
             * */
            [Bindable]
            public function set parentScroller(value:Scroller):void {

                if (value && value.viewport) {
                    value.viewport.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, handle, false, 0, true);
                }
                if (value==null && _parentScroller) {
                    value.viewport.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, handle);
                }
                _parentScroller = value;
            }


            /**
             * Add listener to parent component when added to the display list
             * */
            protected function addedHandler(event:Event):void {
                if (event.target==event.currentTarget) { 
                    // we could "discover" the scroller here if we wanted
                    // or we could just use parentScroller property
                    owner.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, handle, false, 0, true);
                }
            }

            /**
             * Remove listener to parent component when removed to the display list
             * */
            protected function removedHandler(event:Event):void {
                if (event.target==event.currentTarget) {
                    owner.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, handle);
                }
            }

            /**
             * Handle parent or ancestor scroll position changes
             */
            private function handle(e:PropertyChangeEvent):void {
                if (e.source == e.target && e.property == "verticalScrollPosition") {
                    //trace(e.property, "changed to", e.newValue);
                    updateTextFieldPosition();
                }
                if (e.source == e.target && e.property == "horizontalScrollPosition") {
                    //trace(e.property, "changed to", e.newValue);
                    updateTextFieldPosition();
                }
            }

            /**
             * Handles when keyboard activates
             * */
            protected function softKeyboardActivateHandler(event:SoftKeyboardEvent):void {
                updateTextFieldPosition();
            }

            /**
             * Handles when keyboard deactivates
             * */
            protected function softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void {
                updateTextFieldPosition();
            }

            /**
             * Updates the native text fields position
             * */
            public function updateTextFieldPosition():void {
                skin.styleChanged("anything"); // force skin class to revalidate
            }

        ]]>
    </fx:Script>

</s:TextArea>
person 1.21 gigawatts    schedule 21.01.2013