Apache flex Flex Mobile-TileLayout性能问题

Apache flex Flex Mobile-TileLayout性能问题,apache-flex,list,mobile,tiles,flex-mobile,Apache Flex,List,Mobile,Tiles,Flex Mobile,我正在为平板设备构建移动应用程序 我对具有平铺布局的列表组件有很大的性能问题。 我在屏幕上显示大约20-24个项目的页面,用户可以滚动页面。不幸的是,列表组件生成新页面的速度非常慢 总的来说,我测试了具有平铺布局的独立列表,它在每个场景中的性能都非常慢(我在iPad1和iPad2上测试过)。 如果你知道这个问题的一些解决办法,请给我一些建议 谢谢。通常瓷砖的弹性非常慢。这是因为它允许每个项目呈现器的大小可变,并且度量/更新显示列表需要花费大量时间 在这种情况下,我建议您使用定制(自制)的平铺列表


我正在为平板设备构建移动应用程序
我对具有平铺布局的列表组件有很大的性能问题。
我在屏幕上显示大约20-24个项目的页面,用户可以滚动页面。不幸的是,列表组件生成新页面的速度非常慢
总的来说,我测试了具有平铺布局的独立列表,它在每个场景中的性能都非常慢(我在iPad1和iPad2上测试过)。
如果你知道这个问题的一些解决办法,请给我一些建议


谢谢。

通常瓷砖的弹性非常慢。这是因为它允许每个项目呈现器的大小可变,并且度量/更新显示列表需要花费大量时间

  • 在这种情况下,我建议您使用定制(自制)的平铺列表并删除flex组件。如果仅用于布局,则可以手动/编程计算平铺中每个项目的位置,并将其向右移动x/y像素

  • 还要注意效果!它们可以在空气模拟器或桌面浏览器中正常工作,但会占用移动设备上的大量资源

  • 如果您仍然希望使用flex tile组件,而不是创建自己的tile控件,那么我建议您对内部显示的所有项目使用fixed with Renders,并在TileList Decllation中指定columnWidth和rowHeight。这可能会稍微提高性能…:)


  • 另外,放置一些示例代码也没有什么坏处。也许你做错了什么事。。。唐诺:额外的无效,糟糕的渲染等等

    已经有一段时间了,所以我不记得具体细节了。下面是我使用的代码,但请记住,我编写的组件是用于特定目的的,并且包含一些不良实践,可以在很短的时间内完成特定问题。不过,我希望能有所帮助

    页面列表

    package components.pagedList
    {
        import components.pagedList.vo.PageItemVo;      
        import mx.collections.ArrayCollection;
        import mx.collections.IList;
        import mx.core.IFactory;
        import mx.core.UIComponentGlobals;
        import mx.events.CollectionEvent;
        import mx.events.CollectionEventKind;
    
        import spark.components.List;
        import spark.layouts.HorizontalLayout;
    
    /**
     * 
     */
    public class PagedList extends List
    {
    
    
        //--------------------------------------------------------------------------
        //
        //  Constructor
        //
        //--------------------------------------------------------------------------        
    
        public function PagedList()
        {
            super();
        }
    
    
        //--------------------------------------------------------------------------
        //
        //  Variables
        //
        //--------------------------------------------------------------------------    
    
        /**
         * Dimentions for the inner items should be specifyed because 
         * this component needs to know how many items can be placed in 
         * one page, but don't have the ability to create this items.
         * Default value is 1 to avoid division by zero.
         */
        public var innerItemWidth:Number = 1;
    
        public var innerItemHeight:Number = 1;
    
        /**
         * When inner item dimentions are set the component calculates how many items 
         * (per row and col) can be shown on one scren and pass these data to the page 
         * trough the dataProvider for the page.
         */
        private var pageRowCount:int = 1;
    
        private var pageColCount:int = 1;   
    
        /**
         * Count of the items that can fit in one page.
         * This count is used to slice the data into picies
         * with the same length. 
         */
        private var itemsPerPage:int = 0;   
    
        /**
         * Original data provider is saved here so we can re-slice it when
         * size change occure and listen for data change event.
         * 
         * TODO: implement the data chage listener
         */
        private var _originalDataProvider:IList;
    
        /**
         * 
         */
        private var cachedUnscaledWidth:Number = 0;
        private var cachedUnscaledHeight:Number = 0;
    
        //----------------------------------
        //  Custom tiles data
        //----------------------------------
    
        private var _customTilesData:Array;
    
        private var customTilesDataChanged:Boolean;
    
        public function set customTilesData(value:Array):void
        {
            _customTilesData = value;
            customTilesDataChanged = true;
            invalidateProperties();
        }
    
        public function get customTilesData():Array
        {
            return _customTilesData;
        }
    
        //----------------------------------
        //  dataProvider
        //----------------------------------
    
        private var originalDataProviderChanged:Boolean;
    
        [Inspectable(category="Data")]  
        /**
         * 
         */
        override public function set dataProvider(value:IList):void
        {
            if (_originalDataProvider)
                _originalDataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE, originalDataProvider_collectionChangeHandler);     
    
            originalDataProviderChanged = true;
    
            if (value)
                value.addEventListener(CollectionEvent.COLLECTION_CHANGE, originalDataProvider_collectionChangeHandler, false, 0, true);
    
            _originalDataProvider = value;
            updatePagedData();
        }   
    
        /**
         * 
         */
        private function originalDataProvider_collectionChangeHandler(event:CollectionEvent):void
        {
            //trace('data changed:', event.kind, 'location:', event.location);
            if (event.kind == CollectionEventKind.REPLACE)
            {
                updateReplacedItem(event.location);
            }
    
        }   
    
        /**
         * 
         */
        private function updateReplacedItem(index:int):void
        {
            if (dataProvider)
            {
                var pageNumber:int = int(index / itemsPerPage);
                var itemIndex:int = index - (pageNumber * itemsPerPage);
                if (dataProvider[pageNumber])
                {
                    var pageData:PageItemVo = PageItemVo(dataProvider[pageNumber])
                    pageData.data[itemIndex] = _originalDataProvider[index];
                }
            }
        }   
    
        //----------------------------------
        //  innerItemRenderer
        //----------------------------------
    
        private var _innerItemRenderer:IFactory;
    
        private var innerItemRendererChanged:Boolean;
    
        public function set innerItemRenderer(value:IFactory):void
        {
            _innerItemRenderer = value;
            innerItemRendererChanged = true;
            invalidateProperties();
        }
    
        public function get innerItemRenderer():IFactory
        {
            return _innerItemRenderer;
        }
    
    
        //----------------------------------
        //  gaps
        //----------------------------------    
    
        /**
         * 
         */
        public function set verticalGap(value:Number):void
        {
            _verticalGap = value;
            gapsChanged = true;
            invalidateProperties();
        }
    
        public function get verticalGap():Number
        {
            return _verticalGap;
        }
    
        /**
         * 
         */
        public function set horizontalGap(value:Number):void
        {
            _horizontalGap = value;
            gapsChanged = true;
            invalidateProperties();
        }
    
        public function get horizontalGap():Number
        {
            return _horizontalGap;
        }
    
        private var _verticalGap:Number;
    
        private var _horizontalGap:Number;
    
        private var gapsChanged:Boolean;
    
        //--------------------------------------------------------------------------
        //
        //  Overridden methods
        //
        //--------------------------------------------------------------------------
    
        protected function updatePagedData():void
        {
            if (_originalDataProvider)
            {
                var pagedData:IList = createPagedData(_originalDataProvider);
                super.dataProvider = pagedData;
                invalidateProperties();
            }
        }
    
        private function createPagedData(value:IList):IList
        {
            var nestedData:Array = [];
            var dataList:Array = value.toArray();
            var pageData:PageItemVo;
            if (itemsPerPage)
            {
                var customTilesCount:int = customTilesData ? customTilesData.length : 0;
                var normalItemsPerPage:int = itemsPerPage - customTilesCount;
                while (dataList.length)
                {
                    pageData = new PageItemVo();
                    var data:Array = dataList.splice(0, normalItemsPerPage);
                    for (var i:int = 0 ; i < customTilesCount ; i++)
                    {
                        data.push( customTilesData[i] );
                    }
                    pageData.data = new ArrayCollection( data );
                    pageData.colsCount = pageColCount;
                    pageData.rowsCount = pageRowCount;
                    pageData.itemWidth = innerItemWidth
                    pageData.itemHeight = innerItemHeight;
                    pageData.horizontalGap = horizontalGap;
                    pageData.verticalGap = verticalGap;
                    pageData.innerItemRenderer = _innerItemRenderer;
                    nestedData.push(pageData);
                }
            }
            return new ArrayCollection(nestedData);     
        }   
    
        //----------------------------------
        //  Component lifecycle
        //----------------------------------    
    
        override protected function commitProperties():void
        {
            if (gapsChanged || innerItemRendererChanged || customTilesDataChanged)
            {
                updatePagedData();
                gapsChanged = false;
                innerItemRendererChanged = false;
                customTilesDataChanged = false;
            }       
        }
    
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
            caluclateItemsPerPage(unscaledWidth, unscaledHeight);
            // We have to update the dataProvider so it can re-slice the pages 
            // in case of orientation rotation or some other resize
            if (_originalDataProvider)
                if ( cachedUnscaledWidth != unscaledWidth || cachedUnscaledHeight != unscaledHeight )
                    dataProvider = _originalDataProvider;
    
            cachedUnscaledWidth = unscaledWidth;
            cachedUnscaledHeight = unscaledHeight;
        }
    
        protected function caluclateItemsPerPage(unscaledWidth:Number, unscaledHeight:Number):void
        {
            var myLayout:HorizontalLayout = HorizontalLayout(layout);
            var horizontalPaddings:Number = myLayout.paddingLeft + myLayout.paddingRight;
            var verticalPaddings:Number = myLayout.paddingTop + myLayout.paddingRight;
            pageRowCount = (unscaledHeight - verticalPaddings) / (innerItemHeight + verticalGap);
            pageColCount = (unscaledWidth - horizontalPaddings) / (innerItemWidth + horizontalGap);
            itemsPerPage = pageRowCount * pageColCount; 
        }   
    
    
    }
    }
    
    PagedItemVo

    package components.pagedList.vo
    {
        import flash.events.EventDispatcher;
        import flash.events.IEventDispatcher;
    
        import mx.collections.IList;
        import mx.core.IFactory;
    
        [Bindable]
        public class PageItemVo extends EventDispatcher
        {
    
            public var data:IList;
    
            public var rowsCount:int;
    
            public var colsCount:int;
    
            public var itemWidth:Number;
    
            public var itemHeight:Number;
    
            public var verticalGap:Number;
    
            public var horizontalGap:Number;
    
            public var innerItemRenderer:IFactory;
    
            public function PageItemVo(target:IEventDispatcher=null)
            {
                super(target);
            }
        }
    }
    
    滚动列表皮肤

    package skins.pagedList
    {
        import flash.display.Graphics;
        import flash.display.Sprite;
        import flash.events.MouseEvent;
    
        import mx.core.DPIClassification;
        import mx.core.ScrollPolicy;
        import mx.events.FlexEvent;
        import mx.events.TouchInteractionEvent;
    
        import spark.events.IndexChangeEvent;
        import spark.events.RendererExistenceEvent;
        import spark.skins.mobile.ListSkin;
        import spark.skins.mobile.supportClasses.MobileSkin;
    
        public class ScrollingListSkin extends ListSkin
        {
            private var pageIndicator:Sprite;
            private var indicatorSize:uint;
            private var _isHorizontal:Boolean;
            private var _suspendPageIndicatorShortcut:Boolean;
    
            public function ScrollingListSkin()
            {
                super();
    
                switch (applicationDPI)
                {
                    case DPIClassification.DPI_320:
                    {
                        indicatorSize = 32;
                        break;
                    }
                    case DPIClassification.DPI_240:
                    {
                        indicatorSize = 24;
                        break;
                    }
                    default:
                    {
                        indicatorSize = 16;
                        break;
                    }
                }
            }
    
            //--------------------------------------------------------------------------
            //
            //  Overridden methods
            //
            //--------------------------------------------------------------------------
    
            override protected function createChildren():void
            {
                super.createChildren();
    
                scroller.setStyle("skinClass", PagedListScrollerSkin);
    
                // page indicator
                pageIndicator = new Sprite();
    
                // TODO (jasonsj): extend pageIndicator hit area to use the entire 
                // width/height of the List as a shortcut. Currently this only works
                // in the tiny area where the indicators are.
                //pageIndicator.addEventListener(MouseEvent.MOUSE_DOWN, pageIndicaterMouseHandler);
                //pageIndicator.addEventListener(MouseEvent.MOUSE_UP, pageIndicaterMouseHandler);
                //pageIndicator.addEventListener(MouseEvent.MOUSE_MOVE, pageIndicaterMouseHandler);
    
                addChild(pageIndicator);
    
                // listen for changes to the list
                dataGroup.addEventListener(FlexEvent.UPDATE_COMPLETE, dataGroupUpdateComplete);
                scroller.addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_START, touchInteractionStart);
                scroller.addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_END, positionChanged);
            }
    
            override protected function commitProperties():void
            {
                super.commitProperties();
    
                // isHorizontal
                /*var hScrollPolicy:Boolean = getStyle("horizontalScrollPolicy") == ScrollPolicy.ON;
                var vScrollPolicy:Boolean = getStyle("verticalScrollPolicy") == ScrollPolicy.ON;
                _isHorizontal = hScrollPolicy && !vScrollPolicy;*/
                _isHorizontal = true;
            }
    
            override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
            {
                super.drawBackground(unscaledWidth, unscaledHeight);
    
                var pos:Number = (isHorizontal) ? scroller.viewport.horizontalScrollPosition :
                    scroller.viewport.verticalScrollPosition;
                var viewportSize:Number = (isHorizontal) ? scroller.viewport.width :
                    scroller.viewport.height;
    
                var selectedIndex:int = Math.round(pos / viewportSize);
                var numElements:int = dataGroup.numElements;
    
                var g:Graphics = pageIndicator.graphics;
                g.clear();
    
                // if we have only one page there shouldn't be any scrollbar visuals
                if (numElements == 1) return;
    
                var axisPos:Number = 0;
                var centerPos:Number = indicatorSize / 2;
                var radius:Number = indicatorSize / 4;
                //TODO: make so the color could be specifyed outisde 
                var selectionColor:Number = 0x000000; //getStyle("selectionColor");
    
    
                //var elementsPerPage:int = Math.floor(unscaledWidth/FileIconItemRenderer.ITEM_WIDTH) * Math.floor(unscaledHeight/FileIconItemRenderer.ITEM_HEIGHT);
    
                for (var i:uint = 0; i < numElements; i++)
                {
                    if (i == selectedIndex)
                        g.beginFill(selectionColor, 1);
                    else
                        g.beginFill(0, .25);
    
                    if (isHorizontal)
                        g.drawCircle(axisPos + centerPos, centerPos, radius);
                    else
                        g.drawCircle(centerPos, axisPos + centerPos, radius);
    
                    g.endFill();
    
                    axisPos += indicatorSize;
                }
    
                var pageIndicatorX:Number = (isHorizontal) ? (unscaledWidth - axisPos) / 2 :
                    unscaledWidth - (indicatorSize * 1.5);
                var pageIndicatorY:Number = (isHorizontal) ? unscaledHeight - (indicatorSize * 1.5):
                    (unscaledHeight - axisPos) / 2;
    
                setElementPosition(pageIndicator, Math.floor(pageIndicatorX), Math.floor(pageIndicatorY));
            }
    
            override public function styleChanged(styleProp:String):void
            {
                super.styleChanged(styleProp);
    
                var allStyles:Boolean = !styleProp || styleProp == "styleName";
    
                if (allStyles || styleProp == "horizontalScrollPolicy" ||
                    styleProp == "verticalScrollPolicy")
                {
                    invalidateProperties();
                    invalidateDisplayList();
                }
            }
    
            private function get isHorizontal():Boolean
            {
                return _isHorizontal;
            }
    
            //--------------------------------------------------------------------------
            //
            //  Event Handlers
            //
            //--------------------------------------------------------------------------
    
            private function dataGroupUpdateComplete(event:FlexEvent):void
            {
                invalidateDisplayList();
            }
    
            private function touchInteractionStart(event:TouchInteractionEvent):void
            {
                _suspendPageIndicatorShortcut = true;
            }
    
            private function positionChanged(event:TouchInteractionEvent):void
            {
                invalidateDisplayList();
                _suspendPageIndicatorShortcut = false;
            }
    
            private function pageIndicaterMouseHandler(event:MouseEvent):void
            {
                event.preventDefault();
    
                if (_suspendPageIndicatorShortcut)
                    return;
    
                // Mouse events on the pageIndicator sprite will jump to the selected page
                var pos:Number = (isHorizontal) ? event.localX : event.localY;
                var size:Number = (isHorizontal) ? pageIndicator.width : pageIndicator.height;
    
                pos = Math.min(Math.max(pos, 0), size) - (indicatorSize / 2);
    
                var viewportSize:Number = (isHorizontal) ? scroller.viewport.width : scroller.viewport.height;
                viewportSize = viewportSize * dataGroup.numElements;
    
                var viewportPosition:Number = (pos / size) * viewportSize;
    
                if (isHorizontal)
                    scroller.viewport.horizontalScrollPosition = viewportPosition;
                else
                    scroller.viewport.verticalScrollPosition = viewportPosition;
            }
        }
    }
    
    package skins.pagedList
    {
    导入flash.display.Graphics;
    导入flash.display.Sprite;
    导入flash.events.MouseEvent;
    导入mx.core.DPIClassification;
    导入mx.core.ScrollPolicy;
    导入mx.events.FlexEvent;
    导入mx.events.TouchInteractionEvent;
    导入spark.events.IndexChangeEvent;
    导入spark.events.RenderExistenceEvent;
    导入spark.skins.mobile.ListSkin;
    导入spark.skins.mobile.supportClasses.MobileSkin;
    公共类ScrollingListSkin扩展了ListSkin
    {
    私有变量页面指示器:Sprite;
    私人var指标化:uint;
    私有变量水平:布尔值;
    私有变量suspendPageIndicatorShortcut:布尔值;
    公共函数ScrollingListSkin()
    {
    超级();
    开关(applicationDPI)
    {
    案例DPIClassification.DPI_320:
    {
    指标化=32;
    打破
    }
    案例DPIClassification.DPI_240:
    {
    指标化=24;
    打破
    }
    违约:
    {
    指标化=16;
    打破
    }
    }
    }
    //--------------------------------------------------------------------------
    //
    //重写的方法
    //
    //--------------------------------------------------------------------------
    重写受保护的函数createChildren():void
    {
    super.createChildren();
    scroller.setStyle(“skinClass”,PagedListScrollerSkin);
    //页面指示器
    pageIndicator=新精灵();
    //TODO(jasonsj):扩展pageIndicator命中区域以使用整个
    //作为快捷方式的列表的宽度/高度。目前仅此选项有效
    //在指示器所在的小区域。
    //pageIndicator.addEventListener(MouseEvent.MOUSE_DOWN,PageIndicataterMousehandler);
    //pageIndicator.addEventListener(MouseEvent.MOUSE\u UP,PageIndicataterMousehandler);
    //pageIndicator.addEventListener(MouseEvent.MOUSE\u MOVE,PageIndicataterMousehandler);
    addChild(页面指示器);
    //倾听列表中的更改
    dataGroup.addEventListener(FlexEvent.UPDATE_COMPLETE,dataGroupUpdateComplete);
    scroller.addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_START,touchInteractionStart);
    scroller.addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_END,位置更改);
    }
    重写受保护的函数commitProperties():void
    {
    super.commitProperties();
    //水平的
    /*var hScrollPolicy:Boolean=getStyle(“horizontalScrollPolicy”)==ScrollPolicy.ON;
    var vScrollPolicy:Boolean=getStyle(“垂直滚动策略”)==ScrollPolicy.ON;
    _isHorizontal=hScrollPolicy&!vScrollPolicy*/
    _isHorizontal=真;
    }
    覆盖保护功能牵引杆接地(未标度宽度:编号,未标度高度:编号):无效
    {
    超级牵引地面(无刻度宽度、无刻度高度);
    变量位置:数字=(isHorizontal)?scroller.viewport.horizontalScrollPosition:
    scroller.viewport.verticalScrollPosition;
    var viewportSize:Number=(isHorizontal)?scroller.viewport.width:
    scroller.viewport.height;
    var selectedIndex:int=Math.round(位置/视口大小);
    var numElements:int=dataGroup.numElements;
    变量g:Graphics=pageIndicator.Graphics;
    g、 清除();
    //如果我们只有一个页面,就不应该有任何滚动条的视觉效果
    如果(numElements==1)返回;
    var axisPos:Number=0;
    变量centerPos:Number=指示符化/2;
    变量半径:数字=英寸
    
    package skins.pagedList
    {
        import flash.display.Graphics;
        import flash.display.Sprite;
        import flash.events.MouseEvent;
    
        import mx.core.DPIClassification;
        import mx.core.ScrollPolicy;
        import mx.events.FlexEvent;
        import mx.events.TouchInteractionEvent;
    
        import spark.events.IndexChangeEvent;
        import spark.events.RendererExistenceEvent;
        import spark.skins.mobile.ListSkin;
        import spark.skins.mobile.supportClasses.MobileSkin;
    
        public class ScrollingListSkin extends ListSkin
        {
            private var pageIndicator:Sprite;
            private var indicatorSize:uint;
            private var _isHorizontal:Boolean;
            private var _suspendPageIndicatorShortcut:Boolean;
    
            public function ScrollingListSkin()
            {
                super();
    
                switch (applicationDPI)
                {
                    case DPIClassification.DPI_320:
                    {
                        indicatorSize = 32;
                        break;
                    }
                    case DPIClassification.DPI_240:
                    {
                        indicatorSize = 24;
                        break;
                    }
                    default:
                    {
                        indicatorSize = 16;
                        break;
                    }
                }
            }
    
            //--------------------------------------------------------------------------
            //
            //  Overridden methods
            //
            //--------------------------------------------------------------------------
    
            override protected function createChildren():void
            {
                super.createChildren();
    
                scroller.setStyle("skinClass", PagedListScrollerSkin);
    
                // page indicator
                pageIndicator = new Sprite();
    
                // TODO (jasonsj): extend pageIndicator hit area to use the entire 
                // width/height of the List as a shortcut. Currently this only works
                // in the tiny area where the indicators are.
                //pageIndicator.addEventListener(MouseEvent.MOUSE_DOWN, pageIndicaterMouseHandler);
                //pageIndicator.addEventListener(MouseEvent.MOUSE_UP, pageIndicaterMouseHandler);
                //pageIndicator.addEventListener(MouseEvent.MOUSE_MOVE, pageIndicaterMouseHandler);
    
                addChild(pageIndicator);
    
                // listen for changes to the list
                dataGroup.addEventListener(FlexEvent.UPDATE_COMPLETE, dataGroupUpdateComplete);
                scroller.addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_START, touchInteractionStart);
                scroller.addEventListener(TouchInteractionEvent.TOUCH_INTERACTION_END, positionChanged);
            }
    
            override protected function commitProperties():void
            {
                super.commitProperties();
    
                // isHorizontal
                /*var hScrollPolicy:Boolean = getStyle("horizontalScrollPolicy") == ScrollPolicy.ON;
                var vScrollPolicy:Boolean = getStyle("verticalScrollPolicy") == ScrollPolicy.ON;
                _isHorizontal = hScrollPolicy && !vScrollPolicy;*/
                _isHorizontal = true;
            }
    
            override protected function drawBackground(unscaledWidth:Number, unscaledHeight:Number):void
            {
                super.drawBackground(unscaledWidth, unscaledHeight);
    
                var pos:Number = (isHorizontal) ? scroller.viewport.horizontalScrollPosition :
                    scroller.viewport.verticalScrollPosition;
                var viewportSize:Number = (isHorizontal) ? scroller.viewport.width :
                    scroller.viewport.height;
    
                var selectedIndex:int = Math.round(pos / viewportSize);
                var numElements:int = dataGroup.numElements;
    
                var g:Graphics = pageIndicator.graphics;
                g.clear();
    
                // if we have only one page there shouldn't be any scrollbar visuals
                if (numElements == 1) return;
    
                var axisPos:Number = 0;
                var centerPos:Number = indicatorSize / 2;
                var radius:Number = indicatorSize / 4;
                //TODO: make so the color could be specifyed outisde 
                var selectionColor:Number = 0x000000; //getStyle("selectionColor");
    
    
                //var elementsPerPage:int = Math.floor(unscaledWidth/FileIconItemRenderer.ITEM_WIDTH) * Math.floor(unscaledHeight/FileIconItemRenderer.ITEM_HEIGHT);
    
                for (var i:uint = 0; i < numElements; i++)
                {
                    if (i == selectedIndex)
                        g.beginFill(selectionColor, 1);
                    else
                        g.beginFill(0, .25);
    
                    if (isHorizontal)
                        g.drawCircle(axisPos + centerPos, centerPos, radius);
                    else
                        g.drawCircle(centerPos, axisPos + centerPos, radius);
    
                    g.endFill();
    
                    axisPos += indicatorSize;
                }
    
                var pageIndicatorX:Number = (isHorizontal) ? (unscaledWidth - axisPos) / 2 :
                    unscaledWidth - (indicatorSize * 1.5);
                var pageIndicatorY:Number = (isHorizontal) ? unscaledHeight - (indicatorSize * 1.5):
                    (unscaledHeight - axisPos) / 2;
    
                setElementPosition(pageIndicator, Math.floor(pageIndicatorX), Math.floor(pageIndicatorY));
            }
    
            override public function styleChanged(styleProp:String):void
            {
                super.styleChanged(styleProp);
    
                var allStyles:Boolean = !styleProp || styleProp == "styleName";
    
                if (allStyles || styleProp == "horizontalScrollPolicy" ||
                    styleProp == "verticalScrollPolicy")
                {
                    invalidateProperties();
                    invalidateDisplayList();
                }
            }
    
            private function get isHorizontal():Boolean
            {
                return _isHorizontal;
            }
    
            //--------------------------------------------------------------------------
            //
            //  Event Handlers
            //
            //--------------------------------------------------------------------------
    
            private function dataGroupUpdateComplete(event:FlexEvent):void
            {
                invalidateDisplayList();
            }
    
            private function touchInteractionStart(event:TouchInteractionEvent):void
            {
                _suspendPageIndicatorShortcut = true;
            }
    
            private function positionChanged(event:TouchInteractionEvent):void
            {
                invalidateDisplayList();
                _suspendPageIndicatorShortcut = false;
            }
    
            private function pageIndicaterMouseHandler(event:MouseEvent):void
            {
                event.preventDefault();
    
                if (_suspendPageIndicatorShortcut)
                    return;
    
                // Mouse events on the pageIndicator sprite will jump to the selected page
                var pos:Number = (isHorizontal) ? event.localX : event.localY;
                var size:Number = (isHorizontal) ? pageIndicator.width : pageIndicator.height;
    
                pos = Math.min(Math.max(pos, 0), size) - (indicatorSize / 2);
    
                var viewportSize:Number = (isHorizontal) ? scroller.viewport.width : scroller.viewport.height;
                viewportSize = viewportSize * dataGroup.numElements;
    
                var viewportPosition:Number = (pos / size) * viewportSize;
    
                if (isHorizontal)
                    scroller.viewport.horizontalScrollPosition = viewportPosition;
                else
                    scroller.viewport.verticalScrollPosition = viewportPosition;
            }
        }
    }
    
    <pagedList:PagedList id="displayList" 
                     width="100%" height="100%"
                     itemRenderer="skins.pagedList.PageItemRenderer"
                     innerItemRenderer="components.pagedList.tiles.FolderTileItem"
                     innerItemWidth="146" innerItemHeight="150"
                     skinClass="skins.pagedList.ScrollingListSkin"
                     verticalScrollPolicy="off"
                     horizontalScrollPolicy="on"
                     pageScrollingEnabled="true"
                     horizontalGap="15" verticalGap="20"
                     contentBackgroundAlpha="0"
                     selectionColor="0xFFFFFF">
    <pagedList:layout>
        <s:HorizontalLayout columnWidth="{displayList.width}" 
                            variableColumnWidth="false" 
                            gap="0"
                            paddingTop="30"/>
    </pagedList:layout>