0
votes

Trying to implement "pull down to refresh" I've created the following simple test code (please just add to a new Flash Builder project, with "blank" template, i.e. without navbar):

Screenshot:

enter image description here

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>

This seems to work well and the _hint visibility is being toggled just once per pull (I've verified this with a trace).

However when I uncomment the updateList() call above (simulating data fetch from a web server) - everything breaks, the hint.visible=true is being set again and again and the _list is flickering.

Does anybody please have a suggestion, how to fix my poor man's pull to refresh?

1
Is it possible that when you add items to the arraycollection the scroll value / position is being affected? This would (possibly) call into 'handleScroll' again - thus flickering?ethrbunny
Probably... Any suggestions how to workaround this?Alexander Farber
Maybe you could disconnect the arraycollection from your view while you refresh it. Or do your loading into a new ac and then swap them after all the additional data has been inserted.ethrbunny
if hint is already visible in handlescroll then don't update list. and hide hint not by timeoutm but when user releases mouse.user1875642

1 Answers

1
votes

I've ended up with this solution based on Michaël CHAIZE blog entry:

enter image description here

TestPull.mxml (add to a new Flex Mobile project):

<?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>