Как мне реализовать бесконечный список в Flex (hero)

#flash #apache-flex #flex4 #blackberry-playbook #flashlite

#flash #apache-flex #flex4 #blackberry-сборник пьес #вспышка

Вопрос:

Я новичок в Flex / ActionScript (до сих пор .NET / Java были моей основной игровой площадкой). Я пытаюсь создать приложение Flex, в котором есть список, который должен выглядеть и вести себя как бесконечный список (элементов — который может быть любым объектом). Идея в том, что пользователь должен иметь возможность прокручивать вверх или вниз и никогда не доходить до конца списка в любом направлении.

Примером может быть список чисел. Прокрутка вверх покажет отрицательные числа; прокрутка вниз покажет положительные. Теперь мой список представляет собой простой список Flex Spark (с использованием Flex Hero). Он привязан к поставщику данных, который является ArrayList.

Моей первоначальной идеей было прослушать событие прокрутки и добавлять / удалять элементы по мере необходимости. Однако в текущей сборке Flex Hero есть ошибка, из-за которой иногда не возникают события прокрутки для вертикальных полос прокрутки (http://bugs.adobe.com/jira/browse/SDK-26533 ).

Итак, я использую обходной путь, предложенный по ссылке выше (т. е. прослушивание события PropertyChanged окна просмотра прокрутки списка. Событие, однако, дает мне только текущее положение verticalScrollPosition.

И похоже, что список spark по умолчанию поддерживает плавную прокрутку и вызывает событие много раз, прежде чем прокрутка списка остановится (это приятный визуальный эффект).

Теперь мне нужно :

  1. Выясните, выполняется ли прокрутка вверх или вниз (как мне это сделать?)
  2. Выясните, какие элементы видны. Я могу получить это из:

    list.dataGroup.getItemIndicesInView()

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

Я пробовал следующий код, но он не работает. (комментарии в коде).

Есть какие-нибудь эксперты по Flex? Пожалуйста, помогите.


         import mx.collections.ArrayList;
        import mx.core.INavigatorContent;
        import mx.events.FlexEvent;
        import mx.events.PropertyChangeEvent;

        var listData:ArrayList;
        var firstItemInView:int = 0;
        var lastItemInView:int = 0;
        var count = 0;

                    //gets the currently visible item indices (first and last)
        private function getVisibleIndices():Vector.<int> { 
            var ind:Vector.<int> = new Vector.<int>(2, true);
            ind[0] = firstItemInView;
            ind[1] = lastItemInView;
            return ind;
        }

        protected function view_creationCompleteHandler(event:FlexEvent):void {

                            //create an initialise list data
            listData = new ArrayList();
            for(var i:int = 0; i < 6; i  ){
                listData.addItemAt(i, i);
            }
            infiniteList.dataProvider = listData;

            updateIndices();

            infiniteList.scroller.viewport.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, infiniteList_VerticalScroll_PropertyChanged);              
        }

                    //get the indices visible from the list's data group
        private function getNewIndices():Vector.<int> {
            var indices:Vector.<int> = new Vector.<int>(2, true);
            var indicesInView:Vector.<int> = infiniteList.dataGroup.getItemIndicesInView();
            if (indicesInView.length > 0){
                indices[0] = indicesInView[0];
            } 
            if (indicesInView.length > 1){
                indices[1] = indicesInView[indicesInView.length - 1];
            }
            return indices;
        }

        private function updateIndices():void {
            var indices:Vector.<int> = getNewIndices();
            if (indices.length > 0){
                firstItemInView = indices[0];
                if (indices.length > 1){
                    lastItemInView = indices[1];
                }
            }
        }

        protected function leftCalendar_VerticalScroll_PropertyChanged(event:PropertyChangeEvent):void {


            switch (event.property){
                case "verticalScrollPosition":

                    var indices:Vector.<int> = getNewIndices();
                    var oldIndices:Vector.<int> = getVisibleIndices();

                    var newNum:Number;


                    if (indices[1] - indices[0] == 2 amp;amp; (oldIndices[0] != indices[0] amp;amp; oldIndices[1] != indices[1])){
                        //a new item is in view. did we scroll up or down?
                        if (oldIndices[0] < indices[0]){
                            count  ;
                            trace(count   " up : old["   oldIndices[0]   ","   oldIndices[1]   "], new["   indices[0]   ","   indices[1]   "]");
                            //newNum = Number(listData.getItemAt(listData.length - 1))   1;
                            //trace("new number to add: "   newNum);
                            //trace("todo remove: "   listData.getItemAt(0));
                            fixItems({ addAt : "top", removeAt : "bottom", newValue : newNum});

                        } else {
                            trace("down : old["   oldIndices[0]   ","   oldIndices[1]   "], new["   indices[0]   ","   indices[1]   "]");                               
                            fixItems({ addAt : "bottom", removeAt : "top", newValue : newNum});
                        }

                        //update indices:
                        updateIndices();
                        var newOnes = getVisibleIndices(); //seems to be getting the new ones, but the next occurance of this event handler doesn't pick up the new values! why?
                        trace(count   " current["   newOnes[0]   ", "   newOnes[1]   "]");
                    }

                    break;
            }
        }

        protected function fixItems(data:Object):void {
            var item:Object;

            //add a new item
            if (data.addAt == "top"){
                listData.addItemAt(data.newValue, 0);
            } else {
                listData.addItem(data.newValue);
            }

            //remove one of the existing ones
            if (data.removeAt == "top"){
                item = listData.getItemAt(0);
                trace("removing "   item);
                listData.removeItemAt(0);
            } else {
                item = listData.getItemAt(listData.length - 1);
                trace("removing "   item);
                listData.removeItemAt(listData.length - 1);
            }
            updateIndices();
        }
  

Ответ №1:

Вы не можете использовать список. Вам придется создать свой собственный компонент для этого с нуля. Все компоненты, о которых я знаю в Flex, используют конечный dataProvider для отображения информации. Если вы хотите бесконечный, вам нужно создать свой собственный компонент, который может обрабатывать диапазон (или вообще ничего), отображать его соответствующим образом и прокручивать. Обязательно очистите все элементы, которые больше не отображаются (или повторно используйте их), потому что это приведет к серьезной утечке памяти.

Комментарии:

1. ^^^ что он сказал. Вам, безусловно, потребуется реализовать свою собственную логику прокрутки.

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

3. Вам следует изучить жизненный цикл компонента . В Интернете есть много ресурсов для этого. Возможно, вы также захотите взглянуть на серию » Гибкий график за неделю «.

Ответ №2:

Я думаю, вам нужно создать свой пользовательский элемент управления списком, который распространяет элемент arraycollection / arraylist для пользовательского интерфейса, ArrayCollection / Array / ArrayList следует использовать только для хранения данных, таких как линейный список элементов, а элемент управления списком должен отображать элементы циклическим образом

ОТРЕДАКТИРОВАНО Я пытаюсь ответить на ваш вопрос, изменяя данные в списке и направление прокрутки, надеюсь, это поможет

 <?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.events.ScrollEvent;

            [Bindable]
            private var arr:Array = new Array(0,1,2,3,4,5);

            private var lastScrollPostion:int =0;
            private var isScrollingUp:Boolean = false;
            private function ltClicked(event:MouseEvent):void
            {
                arr.unshift(arr[0]-1);
                lst.dataProvider = arr;
            }
            private function rtClicked(event:MouseEvent):void
            {
                arr.push(arr[arr.length-1]  1); 
                lst.dataProvider = arr;
            }

            private function scrolled(event:ScrollEvent):void
            {
                if (lastScrollPostion < event.position)
                {
                    isScrollingUp = false;
                }
                else
                {
                    isScrollingUp = true;
                }
                lastScrollPostion = event.position;
                Alert.show("isScrollingUp : " isScrollingUp.toString());
            }

        ]]>
    </mx:Script>
    <mx:VBox>
        <mx:List 
            id="lst" 
            width="100%" 
            dataProvider="{arr}"
            scroll="{scrolled(event)}"
            />
        <mx:HBox>
            <mx:Button id="lt" label="amp;<amp;<" click="{ltClicked(event)}"/>
            <mx:Button id="rt" label="amp;>amp;>" click="{rtClicked(event)}"/>
        </mx:HBox>

    </mx:VBox>


</mx:Application>
  

ПРИМЕЧАНИЕ
Функции ltClicked и rtClicked изменяют данные списка
и прокрутка используется для перехода к направлению

Я думаю, что лучший способ сделать это — расширить элемент управления списком, чтобы получить направление и положение прокрутки, и манипулировать массивом, чтобы добавлять или удалять элементы в списке

Комментарии:

1. Не уверен, что это сработает. Как бы вы отображали список целых чисел от бесконечности до бесконечности, используя список?

2. Для целых чисел должно быть вычисленное значение, вычисляемое и обновляемое по щелчку пользователя. и новое значение — это нажатие / отмена сдвига в массиве

3. Спасибо — но обновление должно происходить при прокрутке, а не при нажатии пользователем. Также поможет реализация / пример. Я не борюсь с концепцией / идеей / логикой. Мне нужна реализация и реальные API для использования, поскольку я новичок в платформе Flex, но я много работал с .NET / Silverlight.

4. Еще раз спасибо — но я использую список Spark Flex 4.5, а не список mx. Список spark дает мне плавный анимированный эффект прокрутки. (Я создаю приложение для планшетного устройства — Blackberry Playbook, поэтому эффект прокрутки необходим). Я использую очень похожую на вашу логику, но она работает не так, как я хочу.

5. хорошо, вы пытаетесь реализовать тип списка контактов list, если да, вы можете использовать scrollposition для перемещения прокрутки сверху и снизу

Ответ №3:

Можно попробовать класс InfiniteScrollList::

 package components
{

import model.InfiniteListModel;
import model.LoadingVO;

import mx.core.ClassFactory;
import mx.events.PropertyChangeEvent;

import spark.components.IconItemRenderer;
import spark.components.List;

import views.itemRenderer.LoadingItemRenderer;

public class InfiniteScrollList extends List
{
    override protected function createChildren():void
    {
        super.createChildren();
        scroller.viewport.addEventListener( PropertyChangeEvent.PROPERTY_CHANGE, propertyChangeHandler );
        itemRendererFunction = itemRendererFunctionImpl;
    }   

    protected function propertyChangeHandler( event : PropertyChangeEvent ) : void
    {
        //trace( event.property, event.oldValue, event.newValue );

        if ( event.property == "verticalScrollPosition" ) 
        {
            if ( event.newValue == ( event.currentTarget.measuredHeight - event.currentTarget.height )) 
            {
                fetchNextPage();
            }
        }
    }

    protected function fetchNextPage() : void
    {
        if ( dataProvider is InfiniteListModel )
            InfiniteListModel( dataProvider ).getNextPage();
    }

    private function itemRendererFunctionImpl(item:Object):ClassFactory 
    {
        var cla:Class = IconItemRenderer;
        if ( item is LoadingVO )
            cla = LoadingItemRenderer;
        return new ClassFactory(cla);
    }
}
}
  

Класс InfiniteListModel:

 package model
{
    import flash.events.Event;
import flash.utils.setTimeout;

import mx.collections.ArrayCollection;
import mx.rpc.AsyncToken;
import mx.rpc.Responder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.RemoteObject;

public class InfiniteListModel extends ArrayCollection
{
    private var _remoteObject : RemoteObject;

    protected var _loading : Boolean = false;

    public function get remoteObject():RemoteObject
    {
        return _remoteObject;
    }

    public function set remoteObject(value:RemoteObject):void
    {
        _remoteObject = value;
        if ( _remoteObject )
            getNextPage();
    }

    public function InfiniteListModel(source:Array=null)
    {
        super(source);
        addItem( new LoadingVO() );
    }

    public function getNextPage() : void
    {
        if ( !_loading)
        {
            _loading = true;

            trace( "fetching data starting at "   (this.length-1).toString() );
            var token : AsyncToken = remoteObject.getData( this.length-1 );
            var responder : Responder = new Responder( resultHandler, faultHandler );
            token.addResponder( responder );
        }
    }

    protected function resultHandler(event:ResultEvent):void
    {
        this.disableAutoUpdate();

        if ( this.getItemAt( this.length-1 ) is LoadingVO )
            this.removeItemAt( this.length-1 );

        for each ( var item : * in event.result )
        {
            addItem( item );
        }
        addItem( new LoadingVO() );
        this.enableAutoUpdate();

        _loading = false;
    }

    protected function faultHandler(event:FaultEvent):void
    {
        trace( event.fault.toString() );
    }
}
}
  

Для получения подробной информации, пожалуйста, обратитесь к следующему:
http://www.tricedesigns.com/2011/10/26/infinitely-scrolling-lists-in-flex-applications