AS3 Apple Style Preloader
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
October 1st, 2008 at 11:33 am
Nice piece of work! Thanks for giving the source to it!
October 1st, 2008 at 12:04 pm
I would change alphas of each bar in the circle instead of rotating whole circle.
only not sure which way would be lighter?
thx
October 1st, 2008 at 12:08 pm
thanks for sharing the code .
October 1st, 2008 at 2:35 pm
@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.
October 2nd, 2008 at 9:57 am
[...] ??????????????AS3 Apple Style Preloader?? ?????????????????? import?????????????????????? ???????????????????????????? [...]
October 3rd, 2008 at 12:18 am
Thanks a lot Steven.
October 6th, 2008 at 1:03 pm
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.
October 9th, 2008 at 1:57 am
[...] Steven Sacks's original post [...]
October 9th, 2008 at 11:02 am
Thanks for pointing that out, Nick. I've updated the class.
October 18th, 2008 at 4:38 pm
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
October 29th, 2008 at 12:56 pm
What does it look like? The example hangs on load.
October 29th, 2008 at 1:28 pm
You're hilarious.
October 31st, 2008 at 10:28 am
I know. I know.
haha
October 31st, 2008 at 1:00 pm
The best list of Flash tutorial information is at http://www.flashbasics.com
November 3rd, 2008 at 12:44 pm
You are my hero!!! thanks to you i didn´t have to write the code!!!
November 10th, 2008 at 10:30 am
Hey, I am a designer…how do I implement the .as you provided?? Please let know, thx!
November 19th, 2008 at 1:55 am
[...] ?preloader?????????? AS3 Apple Style Preloader [...]
November 21st, 2008 at 4:16 pm
isn't that copyrighted by steve jobs?
November 29th, 2008 at 9:56 am
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?
December 2nd, 2008 at 9:02 am
thats great, now we can all make websites that look like osx… as if shiney buttons were not enough…?
December 6th, 2008 at 11:46 pm
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
December 7th, 2008 at 10:41 am
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);
December 11th, 2008 at 8:59 am
Thanks, Steve! Looks great and so easy! I couldn't figure out how to make it work, looks so easy with the Drawing API:)
December 16th, 2008 at 4:52 am
It's great, do you have it in AS2,
thanks
hania
December 23rd, 2008 at 7:47 pm
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.
January 1st, 2009 at 4:49 pm
@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.
January 20th, 2009 at 10:52 am
[...] AS3 Apple Style Loader If you dig the Apple loader, this is a hand bit of AS3 loader code: [...]
January 30th, 2009 at 4:27 pm
this is great men
tnks for sharing ur knowledge
i just have a little question
how can i put it in a fixed position?
January 30th, 2009 at 9:35 pm
i already solve it,
import net.stevensacks.preloaders.CircleSlicePreloader;
var preloader:CircleSlicePreloader = new CircleSlicePreloader();
preloader.x = 150;
preloader.y = 100;
addChildAt(preloader,0);
February 5th, 2009 at 8:30 am
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
}
}
}
}
March 3rd, 2009 at 1:34 pm
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 ?
March 22nd, 2009 at 2:26 pm
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;
}
March 24th, 2009 at 3:43 am
awesome.
thank you.
April 24th, 2009 at 9:26 pm
Works great! Thanks for sharing.
April 30th, 2009 at 2:11 am
@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!!!
May 12th, 2009 at 10:18 am
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!
August 1st, 2009 at 5:55 am
Steven,
I wrote you on Twitter (@gasi) but you've probably missed it. I love this spinner and I was wondering under which license it can be used?
Cheers,
Daniel
August 4th, 2009 at 12:53 pm
Can I use this to preload a flv file?
August 11th, 2009 at 11:26 am
How do i get it to load a main movie and disappear as it is it stays
September 24th, 2009 at 2:19 pm
I'm using this all over the fracking place in my latest project. Thanks so much!
December 25th, 2009 at 10:09 am
Hi Thanx for the code. I do know how to implement the code and make it work. Could anyone please write a step by step tutorialn how to make it work?
Many thanx
January 13th, 2010 at 11:54 pm
Thank for the code its awesome yaar
March 17th, 2010 at 4:28 am
Thank you! It is simple and useful. I passed with a color parameter:
var preload:CircleSlicePreloader=new CircleSlicePreloader(12, 6, 0xFF0000);
//on the constructor:
private var color:uint
public function CircleSlicePreloader(slices:int, radius:int, color:uint)
{…
this.color = color;
…
}
// and for the slice creation:
private function getSlice():Shape
{
…
slice.graphics.beginFill(color);
…
}
I don`t know if I made it clear…
Thanks again.
March 17th, 2010 at 11:51 am
This is great! Thank you so much. Is there any way to add a dynamic text box below the loader that shows the % loaded?
March 17th, 2010 at 12:00 pm
I added the % loaded below the loader by creating a dynamic text box on stage with an instance name of "percent_loaded". Then, changed the code to this:
import net.stevensacks.preloaders.CircleSlicePreloader;
var preloader:CircleSlicePreloader = new CircleSlicePreloader();
preloader.x = 150;
preloader.y = 100;
addChildAt(preloader,0);
this.loaderInfo.addEventListener (ProgressEvent.PROGRESS, PL_LOADING);
function PL_LOADING(event:ProgressEvent):void {
var percent:Number=event.bytesLoaded/event.bytesTotal*100;
perc_loaded.text=int(percent)+"%";
}
Again, thank you for this code Steven.
March 17th, 2010 at 12:01 pm
DO NOT USE THE ABOVE. TYPO.. Here is the correct code:
import net.stevensacks.preloaders.CircleSlicePreloader;
var preloader:CircleSlicePreloader = new CircleSlicePreloader();
preloader.x = 150;
preloader.y = 100;
addChildAt(preloader,0);
this.loaderInfo.addEventListener (ProgressEvent.PROGRESS, PL_LOADING);
function PL_LOADING(event:ProgressEvent):void {
var percent:Number=event.bytesLoaded/event.bytesTotal*100;
percent_loaded.text=int(percent)+"%";
}