【问题标题】:How do I implement a infinite list in Flex (hero)如何在 Flex 中实现无限列表(英雄)
【发布时间】:2011-08-03 14:39:56
【问题描述】:

我是 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. 根据需要添加/删除项目,以便用户可以永远上下滚动,永远不会到达列表的末尾。

我尝试了以下代码,但它不起作用。 (代码中的 cmets)。

那里有 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 && (oldIndices[0] != indices[0] && 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();
        }

【问题讨论】:

    标签: flash apache-flex flex4 blackberry-playbook flashlite


    【解决方案1】:

    您不能使用列表。您必须从头开始为此创建自己的自定义组件。我所知道的 Flex 中的所有组件都使用有限的 dataProvider 来显示信息。如果您想要无限,则需要创建自己的组件来处理范围(或不处理范围)并适当地显示并滚动它。请务必清理所有不再显示的项目(或重复使用它们),因为这将导致严重的内存泄漏。

    【讨论】:

    • ^^^ 他说的。您肯定需要实现自己的滚动逻辑。
    • 谢谢,我也有同样的结论。 (到目前为止)最大的问题是清理不可见的项目。
    • 您应该查看component lifecycle。这方面网上有很多资源。您可能还想查看Flex in a week 系列。
    【解决方案2】:

    我认为你需要创建你的自定义列表控件,它为 UI 循环 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="&lt;&lt;" click="{ltClicked(event)}"/>
                <mx:Button id="rt" label="&gt;&gt;" click="{rtClicked(event)}"/>
            </mx:HBox>
    
        </mx:VBox>
    
    
    </mx:Application>
    

    注意 函数 ltClicked 和 rtClicked 正在修改 List 数据 并且滚动用于到达方向

    我认为更好的方法是扩展 List 控件以获取方向和滚动位置 并操作 Array 以添加或删除列表中的项目

    【讨论】:

    • 不确定这是否可行。您将如何使用列表显示整数列表 -infinity 到 +infinity?
    • 对于整数应该是计算值,计算并在用户点击时更新。新值是数组中的推送/取消移位
    • 谢谢 - 但更新应该在滚动时发生 - 而不是用户点击。此外,实现/示例将有所帮助。我并没有为概念/想法/逻辑而苦苦挣扎。这是我需要的实现和实际使用的 API——因为我是 Flex 平台的新手——但我已经做了很多 .NET/Silverlight。
    • 再次感谢 - 但我使用的是 Flex 4.5 Spark 列表 - 而不是 mx 列表。火花列表给了我一个平滑的动画滚动效果。 (我正在为平板设备构建一个应用程序——Blackberry Playbook,所以需要滚动效果)。我使用了与您的非常相似的逻辑,但没有按照我想要的方式工作。
    • okies,您是否尝试实现联系人列表类型列表,如果是,您可以使用 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/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-06
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      • 2017-04-16
      相关资源
      最近更新 更多