AS3 Apple Style Preloader

October 1st, 2008 by Steven Sacks

If you want an easy way to get an Apple style preloader for AS3, as seen below, it's as simple as this class, which uses the Flash Drawing API, so it's extremely light.


Download CircleSlicePreloader.as

package net.stevensacks.preloaders
{
        import flash.events.TimerEvent;
        import flash.events.Event;
        import flash.display.Sprite;
        import flash.display.Shape;
        import flash.utils.Timer;

        public class CircleSlicePreloader extends Sprite
        {
                private var timer:Timer;
                private var slices:int;
                private var radius:int;

                public function CircleSlicePreloader(slices:int = 12, radius:int = 6)
                {
                        super();
                        this.slices = slices;
                        this.radius = radius;
                        draw();
                        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
                }
                private function onAddedToStage(event:Event):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
                        addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
                        timer = new Timer(65);
                        timer.addEventListener(TimerEvent.TIMER, onTimer, false, 0, true);
                        timer.start();
                }
                private function onRemovedFromStage(event:Event):void
                {
                        removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
                        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
                        timer.reset();
                        timer.removeEventListener(TimerEvent.TIMER, onTimer);
                        timer = null;
                }
                private function onTimer(event:TimerEvent):void
                {
                        rotation = (rotation + (360 / slices)) % 360;
                }
                private function draw():void
                {
                        var i:int = slices;
                        var degrees:int = 360 / slices;
                        while (i--)
                        {
                                var slice:Shape = getSlice();
                                slice.alpha = Math.max(0.2, 1 - (0.1 * i));
                                var radianAngle:Number = (degrees * i) * Math.PI / 180;
                                slice.rotation = -degrees * i;
                                slice.x = Math.sin(radianAngle) * radius;
                                slice.y = Math.cos(radianAngle) * radius;
                                addChild(slice);
                        }
                }
                private function getSlice():Shape
                {
                        var slice:Shape = new Shape();
                        slice.graphics.beginFill(0x666666);
                        slice.graphics.drawRoundRect(-1, 0, 2, 6, 12, 12);
                        slice.graphics.endFill();
                        return slice;
                }
        }
}

Posted in Actionscript, Flash, Tips/Tricks

36 Responses

  1. Angel Romero

    Nice piece of work! Thanks for giving the source to it!

  2. Armen

    I would change alphas of each bar in the circle instead of rotating whole circle.
    only not sure which way would be lighter?

    thx

  3. zz

    thanks for sharing the code .

  4. Steven Sacks

    @armen There's no way that setting the alpha of 12 Shapes every tick is quicker than rotating a single Sprite. It's 12 actions vs 1. ;)

  5. ????tv?? » Apple Style Preloader ?????????????

    [...] ??????????????AS3 Apple Style Preloader?? ?????????????????? import?????????????????????? ???????????????????????????? [...]

  6. Kunj

    Thanks a lot Steven.

  7. Nick

    Looks good, but there should be either a deconstruct or a removed from stage listener in there to stop and de-reference the Timer. Otherwise the preloader will remain in memory indefinitely because Flash won't garbage collect the Timer.

  8. Mac style preloader in ActionScript3 | flashdaweb.com

    [...] Steven Sacks's original post [...]

  9. Steven Sacks

    Thanks for pointing that out, Nick. I've updated the class.

  10. Siah

    Hi Steven. About 6 mo's into AS3 and just getting into studying how to reference external classes. How could I utilize this as a pre-loader for any events that are triggered in my movie globally? Say, every time an image is loaded, or external swf is pulled in?
    Would I reference the class somehow everytime I run each function?
    Thanks, Ahhhh :-)

  11. Jason Fistner

    What does it look like? The example hangs on load.

    :P

  12. Steven Sacks

    You're hilarious.

  13. Jason Fistner

    I know. I know.
    haha

  14. Jery Mason

    The best list of Flash tutorial information is at http://www.flashbasics.com

  15. Hector

    You are my hero!!! thanks to you i didn“t have to write the code!!!

  16. Whatexitru

    Hey, I am a designer…how do I implement the .as you provided?? Please let know, thx!

  17. ???? - ??????????AS3???

    [...] ?preloader?????????? AS3 Apple Style Preloader [...]

  18. felix

    isn't that copyrighted by steve jobs?

  19. mike

    How would you implement this? I'm new to action script, but what line launches the file or files that were loaded? Would you put this on a keyframe in the swf that is loading? or call it externally?

  20. ryan

    thats great, now we can all make websites that look like osx… as if shiney buttons were not enough…?

  21. matt

    i don't get it do i just open up a new file and paste all of that into a frame is that it coz it's not working for me

    i'm new to actionscript can u plzz help me

  22. Steven Sacks

    Right-click and save the .as file link and put it in the package folder path net/stevensacks/preloaders. If you don't know what that is, you should do some googling.

    Then all you need to do to add it is

    import net.stevensacks.preloaders.CircleSlicePreloader;

    var preloader:CircleSlicePreloader = new CircleSlicePreloader();
    addChild(preloader);

  23. Kat

    Thanks, Steve! Looks great and so easy! I couldn't figure out how to make it work, looks so easy with the Drawing API:)

  24. Hania

    It's great, do you have it in AS2,

    thanks
    hania

  25. Jill

    Yeah, that's nice. But you don't explain it. You throw code at the wall it's bound to slide and land on the floor. Maybe a good old fashion step by step tutorial could help the people.

    or include a .fla file.

  26. Oliver

    @Steven: some performance-related questions (I'm using it as a cursor replacement during data loading operations and need to keep things as smooth as possible) –
    1) Wouldn't setting cacheAsBitmap to true after the draw method has been called be better for performance?
    2) Is there a need to add and remove the listeners to the ADDED_TO_ / REMOVED_FROM_STAGE events on every call? Surely adding them once in the constructor would suffice?
    3) Is there a reason you generate a new Timer instance every time the spinner is added to the stage? Again surely you could simply declare it in the constructor and adding/removing listeners, resetting, etc. it once removed?
    4) Not a question at all: thanks for sharing!

    @Jill: the fact that Steven has chosen to share the code is enough that you might consider saying thank you.
    Simply as a matter of basic etiquette you shouldn't be demanding a tutorial in any case, but frankly he's made the class so simple to implement that if you know what you are doing getting it up and running is a matter of moments, and if you don't you *really* need to get to grips with the basics of classpaths and how the display list works first: doing so will be a far better way of learning than having your hand held all the way.

    That said this will work (assuming you have the classpath set correctly):

    1) Create a new movie and a document class called Spinner.as
    2) Spinner.as should contain


    package
    {
    import net.stevensacks.preloaders.CircleSlicePreloader;

    import flash.display.Sprite;

    public class Spinner extends Sprite
    {
    private var __preloader:CircleSlicePreloader;

    public function Spinner()
    {
    __preloader = new CircleSlicePreloader();

    addChild(__preloader);
    }
    }
    }

    3) Publish.

  27. Preloader Resources for Flash « Flash 99% Good

    [...] AS3 Apple Style Loader If you dig the Apple loader, this is a hand bit of AS3 loader code: [...]

  28. ces

    this is great men
    tnks for sharing ur knowledge :)
    i just have a little question
    how can i put it in a fixed position?

  29. ces

    i already solve it,

    import net.stevensacks.preloaders.CircleSlicePreloader;

    var preloader:CircleSlicePreloader = new CircleSlicePreloader();
    preloader.x = 150;
    preloader.y = 100;

    addChildAt(preloader,0);

  30. Snoop

    Very good script.

    I want to know how i can change the color after 1 complete rotation.

    I write this script but it doesn't work

    package net.stevensacks.preloaders
    {
    import flash.events.TimerEvent;
    import flash.events.Event;
    import flash.display.Sprite;
    import flash.display.Shape;
    import flash.utils.Timer;

    public class CircleSlicePreloader extends Sprite
    {
    private var timer:Timer;
    private var slices:int;
    private var radius:int;
    private var couleur = new Array("0xec008c","0×0f75bc","0×8cc63f","0xf7941e","0xfff200");
    private var ii=0;
    private var t = 12;

    public function CircleSlicePreloader(slices:int = 12, radius:int = 6)
    {
    super();
    this.slices = slices;
    this.radius = radius;
    draw();

    addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    }
    private function onAddedToStage(event:Event):void
    {
    removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
    timer = new Timer(75);
    timer.addEventListener(TimerEvent.TIMER, onTimer, false, 0, true);
    timer.start();
    }
    private function onRemovedFromStage(event:Event):void
    {
    removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
    addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    timer.reset();
    timer.removeEventListener(TimerEvent.TIMER, onTimer);
    timer = null;

    }
    private function onTimer(event:TimerEvent):void
    {
    rotation = (rotation + (360 / slices)) % 360;

    }
    private function draw():void
    {
    var i:int = slices;
    var degrees:int = 360 / slices;
    t–;
    augmente();
    while (i–)
    {
    var slice:Shape = getSlice();
    slice.alpha = Math.max(0.2, 1 – (0.1 * i));
    var radianAngle:Number = (degrees * i) * Math.PI / 180;
    slice.rotation = -degrees * i;
    slice.x = Math.sin(radianAngle) * radius;
    slice.y = Math.cos(radianAngle) * radius;
    addChild(slice);
    }

    }
    private function getSlice():Shape
    {
    var slice:Shape = new Shape();
    slice.graphics.beginFill(couleur[ii]);
    slice.graphics.drawRoundRect(-1, 0, 2, 6, 12, 12);
    slice.graphics.endFill();
    return slice;
    }
    private function augmente():void
    {
    if (t = 5) {
    ii=0
    }

    }
    }
    }

  31. Thomas

    very usefull ! thanks, but a little question :

    you add a listener for ADDED_TO_STAGE on the method "onRemovedFromStage"

    by this way the clip will stay in flash memory even if the value of the variable is set to "null".

    maybe i'm wrong ?

  32. NiklasMoller

    Hello!
    Thanks for a nice tutorial.
    You inspired me to try a different approach to acheive the same thing.
    I came up with some code that accomplishes the same thing, but without creating unique Shape objects for each segment of the circle…
    I dont know if that will make it more resource efficient, but here you go anyway.
    (Actionscript 3.0)
    (paste into main timeline just to try it, or you can convert it to a class if you want)
    ———————

    //create a sprite that will hold our segmented circle:
    var circleHolder:Sprite = new Sprite();
    addChild(circleHolder);
    circleHolder.x = circleHolder.y = 100;

    var innerRadius:int = 20;
    var outerRadius:int = 30;
    var nrOfSegments:int = 15;
    var degreesPerSegment = 360 / nrOfSegments;
    var center:Point = new Point(0,0);
    //store a reference to the correct graphics object (inside circleHolder sprite)
    var g:Graphics = circleHolder.graphics;

    //move the line to the correct starting point:
    var startPos:Point = new Point();
    startPos.x = center.x + innerRadius * Math.cos( deg2rad(360) );
    startPos.y = center.y + innerRadius * Math.sin( deg2rad(360) );
    g.moveTo(startPos.x, startPos.y);

    //draw the segmented circle inside circleHolder:
    for (var deg=360; deg >= 0; deg -= degreesPerSegment){
    var innerPos:Point = new Point();
    innerPos.x = center.x + innerRadius * Math.cos( deg2rad(deg) );
    innerPos.y = center.y + innerRadius * Math.sin( deg2rad(deg) );

    var outerPos:Point = new Point();
    outerPos.x = center.x + outerRadius * Math.cos( deg2rad(deg) );
    outerPos.y = center.y + outerRadius * Math.sin( deg2rad(deg) );

    g.lineStyle(5, 0xFF0000, (deg/360));
    g.moveTo(innerPos.x, innerPos.y);
    g.lineTo(outerPos.x, outerPos.y);

    }

    //function for converting degrees to radians:
    function deg2rad(deg:Number):Number{
    var rad:Number = deg * (Math.PI / 180);
    return rad;
    }

    //timer for rotating the sprite with the segmented circle:
    var rotateTimer:Timer = new Timer(40);
    rotateTimer.addEventListener(TimerEvent.TIMER, rotateCircle);
    rotateTimer.start();

    function rotateCircle(evt:TimerEvent):void{
    circleHolder.rotation += degreesPerSegment;
    }

  33. kevin

    awesome.

    thank you.

  34. Paul

    Works great! Thanks for sharing. :)

  35. Luca

    @Steven Sacks: Hey maaan, your class is GREAT!!!! I can use it and change a lot of things, good!!! 1 thing I've made is to use colorTransform instead of alpha, so It not blends with background (line 49):

    var m = (100/slices)*i;
    var ct = new ColorTransform(1,1,1,1,m,m,m,0);
    slice.transform.colorTransform = ct;
    //slice.alpha = Math.max(0.2, 1 – (0.1 * i));

    Also, just to play, I've changed the angle:

    slice.rotation = -degrees * i – 15;

    so it's more like a 'spiral' :)

    Again, thank you!!!

  36. Karl

    Mate, a million thx for this :)

    i'm gonna have a play and if i come up with anything you may be interested in, i'll post it back here!

    cheers fella!

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.

About Steven Sacks

I am a professional Flash developer with over 13 years of programming experience. I have consulted for high-profile agencies and companies in San Francisco, Los Angeles, Atlanta and New York, and developed numerous award-winning websites and rich internet applications for clients including Adobe, Fox Sports, FX Networks, Anheuser-Busch, GE, DirecTV, ESPN, The Weather Channel, Home Depot, and Coca-Cola.

I am the author of the open-source Gaia Framework for Adobe Flash, which dramatically reduces development time and makes developing Flash sites much easier.