Spark List в мобильном приложении Flex: потяните вниз, чтобы обновить — с тестовым кодом и снимком экрана

Пытаясь реализовать «потяните вниз, чтобы обновить», я создал следующий простой тестовый код (пожалуйста, просто добавьте в новый проект Flash Builder с «пустым» шаблоном, то есть без панели навигации):

Скриншот:

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

TestPull.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    applicationComplete="init()">

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

            private static const PADDING:uint = 20;

            [Bindable]
            private var _ac:ArrayCollection = new ArrayCollection();

            private function init():void {
                updateList();
                _list.scroller.viewport.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, handleScroll);
            }

            private function updateList():void {
                _ac.source = new Array();
                for (var i:int = 0; i < 42; i++) {
                    _ac.source.push(Math.random());
                }
                _ac.refresh();
            }

            private function handleScroll(e:PropertyChangeEvent):void {
                if (e.source == e.target && e.property == "verticalScrollPosition") {
                    trace(e.property, ': ', e.oldValue, ' -> ', e.newValue);
                    if (e.newValue < -2 * PADDING && 
                        e.oldValue >= -2 * PADDING) {
                        _hint.visible = true;
                        setTimeout(hideHint, 2000);
                        //updateList();
                    }
                }
            }

            private function hideHint():void {
                _hint.visible = false;
            }
        ]]>
    </fx:Script>

    <s:List id="_list"
            dataProvider="{_ac}"
            width="100%" 
            height="100%" />

    <s:Label id="_hint"
             text="Pull down to refresh..."
             width="100%"
             textAlign="center"
             fontStyle="italic"
             backgroundColor="#FFFFCC"
             paddingTop="{PADDING}"
             paddingBottom="{PADDING}"
             visible="false" />
</s:Application>

Кажется, это работает хорошо, и видимость _hint переключается только один раз за каждое нажатие (я проверил это с помощью трассировки).

Однако, когда я раскомментирую вышеприведенный вызов updateList() (имитирующий выборку данных с веб-сервера) - все ломается, hint.visible=true устанавливается снова и снова, а _list мерцает.

У кого-нибудь есть предложение, как исправить мое притяжение бедняка для обновления?


person Alexander Farber    schedule 22.02.2013    source источник
comment
Возможно ли, что когда вы добавляете элементы в коллекцию массивов, это влияет на значение/позицию прокрутки? Это (возможно) снова вызовет «handleScroll» - таким образом, мерцание?   -  person ethrbunny    schedule 22.02.2013
comment
Возможно... Любые предложения, как обойти это?   -  person Alexander Farber    schedule 22.02.2013
comment
Возможно, вы могли бы отключить коллекцию массивов от своего представления, пока вы ее обновляете. Или выполните загрузку в новый ак, а затем поменяйте их местами после того, как все дополнительные данные будут вставлены.   -  person ethrbunny    schedule 22.02.2013
comment
если подсказка уже видна в handlescroll, не обновляйте список. и скрыть подсказку не по таймауту, а когда пользователь отпускает мышь.   -  person user1875642    schedule 23.02.2013


Ответы (1)


Я остановился на этом решении, основанном на блоге Микаэля ШАЙЗЕ запись:

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

TestPull.mxml (добавьте в новый проект Flex Mobile):

<?xml version="1.0" encoding="utf-8"?>
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    applicationComplete="init()">

    <fx:Declarations>
        <s:ArrayCollection id="_ac"/>
        <s:Fade id="_fadeIn" duration="500" alphaFrom="0" alphaTo="1" />
    </fx:Declarations>

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

            private static const PADDING:uint = 20;

            private function init():void {
                updateList();
                _list.dataGroup.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, handleScroll);
            }

            private function handleScroll(event:PropertyChangeEvent):void {
                if (_busy.visible || 
                    event.source != event.target || 
                    event.property != 'verticalScrollPosition') {
                    return;
                }

                if (event.newValue < -3 * PADDING && 
                    event.oldValue >= -3 * PADDING) {
                    _hintDown.visible = true;
                    _hintUp.visible = false;
                    _fadeIn.play([_hintDown]);
                } else if (event.newValue < -6 * PADDING && 
                           event.oldValue >= -6 * PADDING) {
                    _hintDown.visible = false;
                    _hintUp.visible = true;
                    _fadeIn.play([_hintUp]);
                } else if (event.newValue >= -6 * PADDING && 
                           event.oldValue < -6 * PADDING) {
                    _hintDown.visible = true;
                    _hintUp.visible = false;
                    _fadeIn.play([_hintDown]);
                } else if (event.newValue >= -3 * PADDING && 
                           event.oldValue < -3 * PADDING) {
                    _hintDown.visible = false;
                    _hintUp.visible = false;
                }
            }

            private function startLoading(event:MouseEvent):void {
                if (_hintUp.visible) {
                    _busy.includeInLayout = _busy.visible = true;
                    setTimeout(updateList, 5000);
                }
                _hintDown.visible = false;
                _hintUp.visible = false;
            }

            private function updateList():void {
                _ac.source = new Array();
                for (var i:int = 0; i < 42; i++) {
                    _ac.source.push(Math.random());
                }
                _ac.refresh();
                _busy.includeInLayout = _busy.visible = false;
            }

        ]]>
    </fx:Script>

    <s:VGroup width="100%">
        <s:HGroup id="_busy"
                  verticalAlign="baseline"
                  includeInLayout="false" 
                  visible="false">
            <s:BusyIndicator />
            <s:Label text="Loading data..." />
        </s:HGroup>

        <s:List id="_list"
                width="100%"
                contentBackgroundColor="#FFFFFF"
                dataProvider="{_ac}"
                mouseUp="startLoading(event)" />
    </s:VGroup>

    <s:Label id="_hintDown"
             text="↓ Pull down to refresh... ↓"
             width="100%"
             textAlign="center"
             paddingTop="{PADDING}"
             visible="false" />

    <s:Label id="_hintUp"
             text="↑ Release to refresh... ↑"
             width="100%"
             textAlign="center"
             paddingTop="{PADDING}"
             visible="false" />

</s:Application>
person Alexander Farber    schedule 26.02.2013