Flex Arc Preloader Without SparkDownloadProgressBar

There is a lot of flex preloader tutorials all over the internet. If you take a closer look at each, you may notice those all extends DownloadProgressBar or SparkDownloadProgressBar classes. You may decide that these classes do not fit your needs, and it that case you can extend regular Sprite with IPreloaderDisplay implementation. Soon you realize there is some other Preloader in use, that communicates with your custom one through events. Following example contains a preloader implementation that renders a filled arc based on application load progress and RSL load progress. Lets have a look how to handle it properly.

This is an example of Preloader.as file

package sk.yoz.rtw.skins.white.components
{
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.ProgressEvent;
    
    import mx.events.FlexEvent;
    import mx.events.RSLEvent;
    import mx.preloaders.IPreloaderDisplay;
    
    import sk.yoz.rtw.view.utils.GraphicsUtils;
    
    public class Preloader extends Sprite implements IPreloaderDisplay
    {
        private var progressShape:Shape = new Shape;
        private var _preloader:Sprite;
        
        private var progress:Number = 0;
        private var rslProgress:Number = 0;
        
        public function Preloader()
        {
            super();
            
            addChild(progressShape);
            
            addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }
        
        public function get backgroundAlpha():Number
        {
            return 1;
        }
        
        public function set backgroundAlpha(value:Number):void
        {
        }
        
        public function get backgroundColor():uint
        {
            return 0;
        }
        
        public function set backgroundColor(value:uint):void
        {
        }
        
        public function get backgroundImage():Object
        {
            return null;
        }
        
        public function set backgroundImage(value:Object):void
        {
        }
        
        public function get backgroundSize():String
        {
            return "100";
        }
        
        public function set backgroundSize(value:String):void
        {
        }
        
        public function set preloader(value:Sprite):void
        {
            _preloader = value;
            preloader.root.loaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
            preloader.addEventListener(RSLEvent.RSL_PROGRESS, onRSLProgress);
            preloader.addEventListener(FlexEvent.INIT_COMPLETE, onInitComplete);
        }
        
        public function get preloader():Sprite
        {
            return _preloader;
        }
        
        public function get stageHeight():Number
        {
            return 0;
        }
        
        public function set stageHeight(value:Number):void
        {
        }
        
        public function get stageWidth():Number
        {
            return 0;
        }
        
        public function set stageWidth(value:Number):void
        {
            
        }
        
        public function initialize():void
        {
        }
        
        // END of interface
        
        private function dispose():void
        {
            preloader.root.loaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress);
            preloader.removeEventListener(RSLEvent.RSL_PROGRESS, onRSLProgress);
            preloader.removeEventListener(FlexEvent.INIT_COMPLETE, onInitComplete);
            
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
            
            stage.removeEventListener(Event.RESIZE, onStageResize);
        }
        
        private function draw():void
        {
            var perc:Number = (progress + rslProgress) / 2;
            progressShape.graphics.clear();
            progressShape.graphics.beginFill(0x0, 0.7);
            GraphicsUtils.drawSolidArc(progressShape.graphics, 0, 0, 10, 30, -0.25, perc, perc * 50);
        }
        
        private function center():void
        {
            progressShape.x = stage.stageWidth / 2;
            progressShape.y = stage.stageHeight / 2;
        }
        
        private function onProgress(event:ProgressEvent):void
        {
            progress = event.bytesLoaded / event.bytesTotal;
            draw();
        }
        
        private function onRSLProgress(event:RSLEvent):void
        {
            rslProgress = (event.bytesLoaded / event.bytesTotal) / event.rslTotal
                + (event.rslIndex / event.rslTotal);
            draw();
        }
        
        private function onAddedToStage(event:Event):void
        {
            center();
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
            stage.addEventListener(Event.RESIZE, onStageResize);
            addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
        }
        
        private function onRemovedFromStage(event:Event):void
        {
            stage.removeEventListener(Event.RESIZE, onStageResize);
            removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
        }
        
        private function onStageResize(event:Event):void
        {
            center();
        }
        
        private function onInitComplete(event:Event):void
        {
            dispose();
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
}

… drawing arcs with fill inspired by PiXELWiT:

package sk.yoz.rtw.view.utils
{
    import flash.display.Graphics;
    
    public class GraphicsUtils
    {
        public static function drawSolidArc(graphics:Graphics, centerX:Number,
            centerY:Number, innerRadius:Number, outerRadius:Number, 
            startAngle:Number, arcAngle:Number, steps:uint):void
        {
            // Used to convert angles to radians.
            var twoPI:Number = 2 * Math.PI;
            
            // How much to rotate for each point along the arc.
            var angleStep:Number = arcAngle / steps;
            
            // Variables set later.
            var angle:Number;
            
            // Find the coordinates of the first point on the inner arc.
            var xx:Number = centerX + Math.cos(startAngle * twoPI) * innerRadius;
            var yy:Number = centerY + Math.sin(startAngle * twoPI) * innerRadius;
            
            // Store the coordiantes in an object.
            var startPointX:Number = xx;
            var startPointY:Number = yy;
            
            // Move to the first point on the inner arc.
            graphics.moveTo(xx, yy);
            
            // Draw all of the other points along the inner arc.
            for(var i:uint = 1; i <= steps; i++)
            {
                angle = (startAngle + i * angleStep) * twoPI;
                xx = centerX + Math.cos(angle) * innerRadius;
                yy = centerY + Math.sin(angle) * innerRadius;
                graphics.lineTo(xx, yy);
            }
            
            // Determine the ending angle of the arc so you can
            // rotate around the outer arc in the opposite direction.
            var endAngle:Number = startAngle + arcAngle;
            //
            // Start drawing all points on the outer arc.
            for(i = 0; i <= steps; i++)
            {
                // To go the opposite direction, we subtract rather than add.
                angle = (endAngle - i * angleStep) * twoPI;
                xx = centerX + Math.cos(angle) * outerRadius;
                yy = centerY + Math.sin(angle) * outerRadius;
                graphics.lineTo(xx, yy);
            }
            
            // Close the shape by drawing a straight
            // line back to the inner arc.
            graphics.lineTo(startPointX, startPointY);
        }
    }
}

…and a main application.mxml file:

<?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" 
               xmlns:mx="library://ns.adobe.com/flex/mx"
               preloader="sk.yoz.rtw.skins.white.components.Preloader">
...

Where to go from here:

Leave a comment

Please be polite and on topic. Your e-mail will never be published.