Smooth Scrollbar Flash Tutorial

May 10th, 2011 | 16 Comments

So much content and so little space in which to display it.

In this tutorial, I want to discuss the basics of creating scrollable content in ActionScript 3. In our examples, scrollable content will include much more than simple scrollable text fields. For our purposes here, we want to learn how to create scrollable content that can include images, movie clips, and more.

Step 1 – Store Your Content in a Movie Clip

In order to display the power of our custom scrollbar, I am going to include text and Movie Clips within our scrollable content. Once you've built out your content, select all of it and go to Modify > Convert to Symbol. Set the symbol type to "Movie Clip", and call it "mcContent" (or something similar). IMPORTANT: If you want your calculations to work properly, be sure to set the registration point to the upper-left corner of your Movie Clip when you create it, like so:

Registration Point

After creating the Movie Clip, select it on the stage, go to the Properties Panel, and give it an instance name of content_mc. On the stage, your content will look something like this:

Scrollbar Flash

 

Notice that our content, extends past the bottom of the stage: hence our need for scrollable content.

Step 2 – Mask Your Content

The next step is to create a mask that reveals only the area where you want the content to be visible. In this case, our mask will be a simple rectangle with a fill and no stroke that takes up most (but not all) of the height of the stage itself. Be sure to create your mask on a new layer directly above your content layer. I like to use a bright green fill color for my masks, but that's just a personal preference. It doesn't matter what color you use.

After you draw your mask rectangle, select it and convert it to a Movie Clip Symbol. Your mask should look like this:

mask

As a reminder, the mask represents the area of your content that you actually want to be visible. Once the mask is applied, everything outside of the mask will be invisible.

Before applying the mask, double-check to make sure that your mask Movie Clip is on its own layer directly above the layer that contains the content you want to mask. Then, right-click on the layer that contains your mask and click on the "Mask" option. If done properly, the green rectangle should disappear, and you should see only the content that was inside the rectangle, like so:

 

Notice that all of the excess content is now invisible. Only the content that was behind the mask is visible. Now, in order to scroll the content, we just need to animate it behind the mask in response to interaction with a scrollbar.

Step 3 – Build the Scrollbar

Your scrollbar will contain two elements nested into one Movie Clip: the background and the scroller. Each of these items are simple rectangles. Here's what I came up with:

 

 

Like I said, two rectangles. Pretty simple. You can spice it up if you like, but I'm going to stick with the minimalist look for now. Either way, you will end up with two separate Movie Clips: one for the background of your scrollbar and one for the draggable handle that you will use to do the actual scrolling. Give this handle an instance name of scroller_mc. Then select both the scroller and the background and hit F8 to combine them into a single scrollbar Movie Clip. Give this Movie Clip an instance name of scrollbar_mc.

Step 4 – Dragging the Scroller

Your next task is to determine how far up and down your scroller will be able to move. When you drag the scroller, it's obviously not going to move left to right, but you need to figure out how far up and down it will move if you want everything to function properly. To figure this out, double-click on your scrollbar to go into the Movie Clip. Inside the Movie Clip, you should have two more Movie Clips: the background and the scroller. If you placed your scroller at it's beginning location, as in the image above, then you should already be able to determine its beginning y-coordinate. Simply click on the scroller and look at the y-coordinate shown in your Properties panel. In my case, it said 2.95 for the starting y-coordinate. But I want a nice whole number, so I changed the y-coordinate to 3. Whatever number you end up with here, write it down. In fact, go ahead and write down the x-coordinate, too, because you will need it in a few minutes. My (x,y) coordinates for the starting location work out to (4,3).

Next, select your scroller and drag it down to the lowest possible point within the bounds of your background rectangle. This time, you will only need the y-coordinate, so take note of it. In my case, the y-coordinate works out to 312. Your scroll range (the range you'll be able to drag the scroller up and down) will be the different between the ending y-coordinate and the first y-coordinate you wrote down. In my case, the scroll range works out to 312 - 3 = 309. So I should be able to drag my scroller up and down within a range of 309 pixels. So, how do we implement this in ActionScript? Easy!

First of all, move your scroller back to its original position. Then go back to your main timeline, create a new layer, rename the layer Actions, and with frame 1 of that layer selected, hit F9 (or Option+F9 on a Mac) to open up your Actions panel. Enter the following code:

var rect:Rectangle;

scrollbar_mc.scroller_mc.buttonMode = true;
scrollbar_mc.scroller_mc.addEventListener(MouseEvent.MOUSE_DOWN, dragIt);

function dragIt(e:MouseEvent):void {
	rect = new Rectangle(4, 3, 0, 309);
	scrollbar_mc.scroller_mc.startDrag(false, rect);
	stage.addEventListener(MouseEvent.MOUSE_UP, dropIt);
}

function dropIt(e:MouseEvent):void {
	scrollbar_mc.scroller_mc.stopDrag();
}

The first line of code creates a variable where we will store a rectangle that will determine the draggable bounds of our scroller. This variable is being created outside of all functions, because once we actually create the rectangle, we will need to access its properties in more than one place. More on that later.

The next line sets the buttonMode property for the scroller Movie Clip to true. This will cause the scroller to behave like a Button in that it will cause your mouse cursor to turn into the hand cursor when you hover over it.

The third line adds a MOUSE_DOWN listener to the scroller. Think about how a scrollbar works. When you press your mouse button down on the scroller, that's when you want it to start dragging, so that's when our code triggers the "dragIt" function.

Inside the dragIt function I've created a rectangle object. This rectangle will not be drawn on the stage; it will simply be used to determine the bounds of our draggable area for the scroller. When the "new Rectangle()" method is called, you'll notice I entered four different numbers. The first two numbers (4 and 3) determine the x,y coordinates of the rectangle. This should be the same as the beginning x,y coordinates that you wrote down earlier for your scroller Movie Clip. The next two numbers (0, 309) determine the width and height of the rectangle. Since we don't want to be able to drag the scroller left and right, the width of our rectangle is 0. The height of my rectangle, as calculated before, is 309. As you can see, this rectangle was created and stored in a variable called rect.

After creating the rectangle object, we are calling on the startDrag() method and passing in two parameters. The first parameter determines whether or not the center of the object you're dragging will snap to where your mouse cursor is. We don't want this to happen, so we entered false. The second parameter is simply the variable name we gave to the rectangle we just created. Basically, we're telling the startDrag() method to use rect to determine the draggable boundaries of our scroller.

After creating the drag functionality, you need to create the functionality to stop dragging. Notice that I've added this particular listener to the stage instead of to the scroller itself. If you add the MOUSE_UP listener to the object itself, then it will only be triggered if you're still hovering over the Movie Clip when your mouse cursor is released. Adding the listener to the stage, on the other hand, assures us that no matter where our mouse cursor is when we release the mouse button, the dropIt function will be called, and dragging will cease.

Step 5 – Making the Scrollbar Work

In order for your scrollbar to function properly, there is a little bit of math involved. The y-coordinate of your content is going to change in response to the y-coordinate of your scroller. As you drag your scroller up and down, your content will move up and down in the opposite direction. But how much will it move?

Instead of thinking in terms of the number of pixels moved, let's think in terms of percentages. This will make things much easier. For example, if you have dragged your scroller 50% of the way down its scrollable range, then you want your content to move up 50% of its total range. When you think in terms of percentages, this whole solution become easier to wrap your head around.

So, in order to determine a percentage for your scroller, you need two numbers:

  1. The total range of movement for the scroller.
  2. The current y-coordinate within that range, adjusted for it's starting position.

The reason we need to adjust for the starting position is because our scroller doesn't start off at a y-coordinate of 0. In my file, it is at a y-coordinate of 3 within the scrollbar Movie Clip. Let's take a look at a beautifully-rendered Photoshop illustration of what we're doing here:

Scroller Example

Okay, so it's not technically a percentage we're calculating; it's more of a ratio. But you get the point. According to the example above, the current position of the scroller (adjusted for its minimum y-coordinate) is roughly 49.5% of the way down its total range of movement. As a response, we want the content to move to a position 49.5% of the way up its own range of movement, so we'll simply use the same ratio (0.495) to calculate where it needs to be.

Now that I've properly over-explained everything, let's take a look at the final code. Before entering the following code, be sure to give an instance name to the Movie Clip you're using to mask your content. I've given mine an instance name of mask_mc.

var rect:Rectangle;
<strong>var scrollerMinY:Number = scrollbar_mc.scroller_mc.y; var contentMaxY:Number = content_mc.y; var padding:Number = 40;</strong>

scrollbar_mc.scroller_mc.buttonMode = true;
scrollbar_mc.scroller_mc.addEventListener(MouseEvent.MOUSE_DOWN, dragIt);

function dragIt(e:MouseEvent):void {
	rect = new Rectangle(4, 3, 0, 309);
	scrollbar_mc.scroller_mc.startDrag(false, rect);
	stage.addEventListener(MouseEvent.MOUSE_UP, dropIt);
	<strong>scrollbar_mc.scroller_mc.addEventListener(Event.ENTER_FRAME, scrollIt);</strong>
}

function dropIt(e:MouseEvent):void {
	scrollbar_mc.scroller_mc.stopDrag();
        <strong>scrollbar_mc.scroller_mc.removeEventListener(Event.ENTER_FRAME, scrollIt);</strong>
}

<strong>function scrollIt(e:Event):void {</strong>
<strong> var scrollerRange:Number = rect.height; var contentRange:Number = content_mc.height - mask_mc.height + padding; var percentage:Number = (scrollbar_mc.scroller_mc.y - scrollerMinY) / scrollerRange; var targetY:Number = contentMaxY - percentage * contentRange; content_mc.y = targetY; }</strong>

Once you have added the code in bold, you should have a working scrollbar, Flash style!

Hopefully, most of this code speaks for itself, but there are a couple things worth pointing out. First of all, you'll notice a variable I created called "padding". Sometimes, when you create your own custom scrollbar, the content doesn't always scroll up as far as you like when you drag the scroller all the way to the bottom. The padding variable adds a little bit more room to the total range of movement for the content, as seen in the scrollIt() function. The value entered here is completely optional, depending on how your text looks when scrolled.

Also, notice that we've added another line of code inside the dragIt() function. As soon as we start dragging the scroller, this line of code triggers an ENTER_FRAME event, which causes the scrollIt() function to run over and over again at the current framerate. That's how we get the smooth scrolling as we drag up and down. Also, since we've created this event listener, we need to delete it when we're done dragging. This is done in the dropIt() function.

Finally, inside the scrollIt() function, once we calculate the percentage that we discussed before, we use that percentage to place the content where it needs to be. We do this using the following calculation:

contentMaxY - percentage * contentRange

Multiplying the percentage by the contentRange gives us how far the content needs to be moved. This number is subtracted from the maximum y-coordinate of your content to properly offset it.

Here is your final result:

Click here to download the source files

Tags: , , , , , , , , , ,

16 Responses

  1. Tony says:

    Looks like another top notch tutorial !
    Thanks to you Craig, I have learned a lot, keep them coming :)

  2. Very Useful Tutorial pal !! thanks… :)

  3. Great tutorial but what I wanted to know is if there is a tutorial out there that also has the UP and DOWN button arrows on the top and bottom of the scroll bar so I can scroll the content area just a certain amount by clicking.
    I know I can use the ScrollPane in Flash CS5 but I want to be able to build the whole thing myself, can you help?

    Regards Dennis

  4. Van says:

    This tutorial and source file has saved me multiple times. What a useful component. Thank you so much!

  5. informative tutorial
    you seem like a professional writer

  6. amit says:

    Brilliant stuff there Craig! This was so damn simple and it worked wonders. Thumbs Up to the tutorial and to the brains behind it…

  7. Devin says:

    Must have tried 10 different methods before this one…this works perfect, thank you so much!

  8. Stephen says:

    Far and away the best scroller tutorial I have seen!! Well done and thank you!

  9. omker says:

    I tried but it is not working, 4 errors r showing
    1. The class or interface ‘Rectangle’ could not be loaded.
    2. The class or interface ‘MouseEvent’ could not be loaded.
    3. The class or interface ‘MouseEvent’ could not be loaded.
    4. The class or interface ‘Event’ could not be loaded.

    can anyone help me plz, i need a scroller very badly.

  10. Dylan says:

    This turtorial is exactly what I’ve been looking for but I’m still having trouble. I keep getting these two errors:

    Symbol ‘scrollbar’, Layer ‘actions’, Frame 1, Line 13 1151: A conflict exists with definition rect in namespace internal.

    Symbol ‘scrollbar’, Layer ‘actions’, Frame 1, Line 21 1021: Duplicate function definition.

    Any ideas what I might be doing wrong?

  11. Dylan says:

    I’ve been playing more with this and I thought I figured out what I had done wrong with the script…the swf renders now seemingly without error but the scrollbar isn’t functional and I get this typeERROR in the output:

    TypeError: Error #1010: A term is undefined and has no properties.
    at scrollbar_fla::scrollbar_46/frame1()
    at flash.display::MovieClip/gotoAndPlay()
    at scrollbar_fla::MainTimeline/fl_ClickToGoToAndPlayFromFrame_5()

    Any thoughts?

  12. John says:

    Why should I change in ActionScript to scroll this content with mouse whell?

  13. M says:

    Hi!
    Mine works fine, except it keeps scrolling out of the rectangle anyway. How can I fix this? I’ve adapted it a bit to what I needed.

    function dragIt(e:MouseEvent):void{
    rect= new Rectangle(301,280,0,360);
    handle.startDrag(false,rect);
    stage.addEventListener(MouseEvent.MOUSE_UP, dropIt);
    }

    Thanks, great tut,
    M

  14. M says:

    Hi again.
    What if I have my content above the mask instead than under, then I just want it to move down, but how should I change the code for what I need?
    M

  15. stan says:

    or here is a free scroller
    http://www.uniscroller.com scroller comes from one of my project

  16. uday kumar says:

    Looks like another top notch tutorial !
    Thanks to you Craig, I have learned a lot from this!! Thanks once again buddy :)

Leave a Reply