This website uses cookies to improve user experience. By using our website you consent to all cookies in accordance with our Cookie Policy. X

Seek Bar in Flash [basic]

Happy New Year 2012!

Often on the Internet I see people asking how to make a seek bar in a Flash animation (similar to how other video players do it, such as the one used on YouTube) however in the end not many people go through with it - why is that? The answer lays in how Flash handles MovieClips, which is why before I go any further I will take a moment to write few words about them.
It might be hard to visualize it, but each MovieClip is a self contained movie with its own time-line (and settings) and is controlled completely independently of any other objects, which can be seen below (pick any moment, right click and uncheck "play"):

As one might expect the whole animation will be instantly stopped... except for the ball which is a MovieClip. No point in explaining why is that - it just is and will never change. Only thing left to do is to look for alternative solutions, and because stopping all the MovieClips will directly help us with creation of a seek bar it is best to look at two possible workarounds:
1. Remove all the graphics in your animation.
2. Manually stop all the MovieClips with ActionScript.
First solution is the best way to go, as long as you are just starting the creation of your movie, because it is always easier to prepare it beforehand than later convert all the MovieClips into Graphic objects. Afterwards moving around the animation will only require a single call to the gotoAndPlay function, which is exactly what we need for our seek bar. Second solution is only viable in animations with small amount of MovieClips, because seeking and stopping the MovieClips might be a bit too stressful for the processor, especially in the case of a seek bar since it requires a scan through the whole movie. Oh well, sometimes you just don't have a choice.
Code that stops all MovieClip is actually quite simple:
stopMovies(root as MovieClip);
function stopMovies(mc:MovieClip):void {
	for(var i:int = 0; i<mc.numChildren; i++) {
		var d:DisplayObject = mc.getChildAt(i);
		if(d is MovieClip) {
			(d as MovieClip).stop();
			stopMovies(d as MovieClip);
		}
	}
}
Now one might think that the only thing missing here is a gotoAndPlay function and we are set. Unfortunately it is not that simple, as each MovieClip has its own time-line, in will never react to changes in the main time-line (contrary to Graphic objects). Furthermore, replacing every stop function with gotoAndPlay is also pointless as having the main animation on 10th frame does not necessarily mean that each MovieClip is also on the 10th frame - it all comes down to the fact that MovieClip appearing on the, for example, 6th frame, on 10th one will be in 4th frame of its own time-line. It is best to see this in action - animation below has a MovieClip (with 20 frames) appearing on the 10th frame (all of them numbered):
While scrolling, the MovieClip appears to have a mind of his own.
Okay, but why not take the appearing position of the MovieClip and subtract it from the current position? Lets say we want to go to the frame #15 with the MovieClip appearing on the 10th one, so we just take 10 and subtract it from 15 resulting in gotoAndPlay(5) - main time-line stays on 15 while our MovieClip is re-winded to the 5th frame. This is a great idea and perfect solution, but unfortunately Flash has no way of telling us what is the MovieClip's appearing frame. Here is where the challenge for the processor I was talking about earlier comes in, as the next step would be to write down all the starting positions of each MovieClip; which isn't as easy as it sounds, because an animation that takes, for example, 1 minute to play out and is displayed at 20 frames per second, will have 1200 frames worth of scanning! Plus, lets say, 10 MovieClips per frame... Least to say, it is not a very useful solution, which is why for the rest of this article I will assume you are using only Graphic objects.
That is it for theory, time to create our seek bar - taking the bare minimum, we will need MovieClips: a bar representing the length of our whole animation and a marker showing the current position. To make this easier put both of them in a time-line of separate MovieClip (the whole seek bar will be in one place making it easier to, for example, move it between projects) and name them mcBar and mcMarker (instance name). Finally put this code into the time-line of the enclosing MovieClip (one holding the bar and the marker):
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.MovieClip;

var bSeek:Boolean = false;
var nLength:Number = mcBar.width-mcMarker.width;
mcMarker.mouseEnabled = false;
mcMarker.mouseChildren = false;

if( !mcBar.hasEventListener(MouseEvent.MOUSE_DOWN) ) {
	//to prevent unnecessary duplications on each loop
	mcBar.addEventListener(MouseEvent.MOUSE_DOWN,onSeekStart);
	mcBar.stage.addEventListener(MouseEvent.MOUSE_MOVE,onSeekDrag);
	mcBar.stage.addEventListener(MouseEvent.MOUSE_UP,onSeekStop);
	mcBar.stage.addEventListener(Event.ENTER_FRAME,onRender);
}

function onRender(e:Event):void {
	if(bSeek) return;
	mcMarker.x = ((root as MovieClip).currentFrame/(root as MovieClip).totalFrames)*nLength;
}
function onSeekStart(e:MouseEvent):void {
	bSeek = true;
	onSeekDrag(e);
}
function onSeekDrag(e:MouseEvent):void {
	if(!bSeek) return;
	
	mcMarker.x = mcBar.mouseX;
	if(mcMarker.x > nLength) {
		mcMarker.x = nLength;
	} else if(mcMarker.x<0) {
		mcMarker.x = 0;
	}
	
	var frame:int = int((mcMarker.x/nLength)*(root as MovieClip).totalFrames);
	
	(root as MovieClip).gotoAndStop(frame);
	mcMarker.x = (frame/(root as MovieClip).totalFrames)*nLength;
}
function onSeekStop(e:MouseEvent):void {
	bSeek = false;
	(root as MovieClip).play();
}
Nothing particularly complicated here - clicking on the seek bar moves the marker there and translates its X coordinate into the animation's position.
The whole code + an example how to use it can be download from here: seekbar.zip
And for anyone who wants to try the MovieClip scanning solution I prepared a special class and an example to go with it: seekbarEX.zip. In this case, to avoide conflicts with the animation itself, MovieClip which holds both the marker and the bar is exported for ActionScript with ForusSeekBar class.

Name:
Comment:
Confirm the image code:confirm image

 
nazar writes:
18.01.2012 08:22
plz upload the sample file seebarEX.zip for flash cs5 version.

4as writes:
22.01.2012 23:03
Sure, you can now re-download seekbarEX.zip file and it will have CS4 version (so more people can open it).

jason writes:
08.05.2013 19:46
i just tried this and it works except the marker is not synced with the bar properly, the marker starts at half way across the screen and runs off the screen. i am using cs5 action script 3.0, does it matter as 3.0 or 2.0? i'm on a macbookpro 10.6.8

jason writes:
09.05.2013 05:10
I'm having no luck. Can you please explain in better detail, clearly, exactly where everything goes.

jason writes:
09.05.2013 18:17
ok, got it to work again, sort of. my marker starts at the far left of the screen--it is not synced with my bar-- is only grabbed way to the right of the marker, it can't be grabbed exactly on the marker

Naresh writes:
04.07.2013 09:22
Plz upload the sample file seekbar.zip for cs3 version

Kapode writes:
28.03.2014 03:27
Thank you so mush

Jamal writes:
27.12.2016 11:17
On seekbarEX sometimes I got an error "angeError: Error #2006: The supplied index is out of bounds." Plz help. thnks in aadvance

Surya writes:
25.02.2017 14:00
plz upload the sample file seebar.zip for flash cs6 version