How to Build a Basic Toggle Button (AS2)

Flash ActionScript 2.0

kweku and nab have been interested a play/pause button — essentially a toggle button, something that “remembers” when it’s been clicked — and fortunately, the mechanics are fairly simple.  The key to the desired functionality is a Boolean variable.  Let’s take a look. 

Building the button itself

Even though we’re speaking of a “button,” this widget is going to be built out of a movie clip symbol.  Why?  The answer is found in the ActionScript 2.0 classes that define buttons and movie clips:  the Button class doesn’t allow for any way to direct the playhead along its own timeline, while the MovieClip class features two methods (gotoAndPlay() and gotoAndStop()) that do.  By using a movie clip, you’ll find you can create as many custom “button states” as you please and display them visually by sending the movie clip’s timeline to the desired frame.

In a new FLA file, use the Oval tool to draw a circle on the Stage, approximately 42 x 42 pixels.  Select the circle and convert it to a movie clip symbol.  Double click the movie clip to enter its timeline, which brings you back to the circle shape itself.  Select frame 2 and add a new keyframe.  This gives you the original circle on frame 1 and an identical duplicate on frame 2.  Change the color of the circle on frame 2 in a way that looks to you like a highlighted “over” state (the same thing you might do to the Over frame of a button symbol).  Add a blank keyframe to frame 3 and draw a square roughly the same size.  Duplicate to frame 4 and change the colors as appropriate.  (kweku and nab, in your own work, you’ll want to put play/pause artwork on these frames … two frames worth of “play” artwork, default and highlighted, on frames 1 and 2, and two frames worth of “pause” artwork, default and highlighted, on 3 and 4.)

When you’re done, return to the main timeline to add your code.

Coding up the button

Select your new movie clip “button” by clicking on it.  Give it an instance name in the Property inspector.  For the sample code here, I’ll use btnToggle.  Create a new layer for your ActionScript, if you don’t have one already.  In your scripts layer, open the Actions panel and type the following:

btnToggle.stop();
  btnToggle.toggled = false;
btnToggle.onRelease = function():Void {
  this.toggled = !this.toggled; // this flip-flips the Boolean
    if (this.toggled) {
  this.gotoAndStop(3);
    } else {
  this.gotoAndStop(1);
  }
}

Let’s break it down so far.  The first line invokes MovieClip.stop() on the btnToggle instance, which does nothing more than stop its timeline.  Without this line, the movie clip would animate through its four frames as usual, fluttering.  The second line creates a new toggled property on the movie clip and sets its to false by default.  This is effectively the same thing as having typed this …

var toggled:Boolean = false;

… in frame 1 of btnToggle’s own timeline.  It’s just more convenient to keep all our code in one place.

The MovieClip.onRelease event handler is the fun part.  A function is assigned to the onRelease handler of the btnToggle instance.  This function does very little, but what it does do is important.  First, it flip-flops the previously declared Boolean, toggled, to the opposite of whatever it is currently.  This occurs thanks to the logical NOT operator (!).  The expression is simply the following:

this.toggled = !this.toggled;

… which is to say, “The toggled variable’s value in this timeline is being set to ‘NOT the toggled variable’s value’,” which means false is set to true (or true is set to false, as the case may be).  Then it checks the value of toggledif (this.toggled) — and sends the playhead to the relevant frame (note:  the expression if (this.toggled) is just a shorthand way of saying if (this.toggled == true)).

The movie clip begins on frame 1, of course, and toggled defaults to false.  The very first time this function is triggered, it sets toggled to true, then runs through the if statement.  At this point, toggled is true, which means the first clause is performed — this.gotoAndPlay(3), which sends the playhead to frame 3 (the square shape’s “up” artwork).  The next time this function is triggered (because of another mouse click), toggled is set to false and the second clause is performed — this.gotoAndPlay(1) — which sends the playhead back to frame 1.

Introducing over states

If you want the button to show off those “over” states (frames 2 and 4), you’ll need to handle additional events, such as onRollOver and onRollOut.  Check out the new code:

btnToggle.stop();
btnToggle.toggled = false;

btnToggle.onRelease = function():Void {
  this.toggled = !this.toggled; // this flip-flips the Boolean
  if (this.toggled) {
    this.gotoAndStop(4);
  } else {
    this.gotoAndStop(2);
  }
}
btnToggle.onRollOver = function():Void {
  if (this.toggled) {
    this.gotoAndStop(4);
  } else {
    this.gotoAndStop(2);
  }
}
btnToggle.onRollOut = function():Void {
  if (this.toggled) {
    this.gotoAndStop(3);
  } else {
    this.gotoAndStop(1);
  }
}

The toggling itself — an actual change to the toggled variable — only occurs in response to an actual click (onRelease), but the other event handlers note the value of that variable and send the playhead to whatever frames make sense.  Note that in this updated code, frames 3 and 1 in the gotoAndStop() statements have been changed to 4 and 2.  Why?  Well, we’ve introduced highlights (over states), so this time when the artwork is toggled, it should go to the highlighted (over) frame when the change occurs.  After all, the user’s mouse would still be over the movie clip button.  The unhilighted frames, 3 and 1, are only visited when the user’s mouse leaves the button.

Using the button

In actual practice, your toggle button will contain additional code.  You’ll want the button to actually do something, rather than just update visually.  Presumably, you’ll only need to add code to the onRelease handler, but the end result is completely up to you.

btnToggle.onRelease = function():Void {
this.toggled = !this.toggled; // this flip-flips the Boolean
  if (this.toggled) {
    this.gotoAndStop(4);
    // additional code here, for what to do when
    // the button is clicked to its “on” position
  } else {
    this.gotoAndStop(2);
    // additional code here, for what to do when
    // the button is clicked to its “off” position
  }
}

Additionally, you can check the state of your button via ActionScript, simply be referencing its toggled property:

// Code that bases its actions on the state
// of this toggle button …
if (btnToggle.toggled) { … }

13 Responses to “How to Build a Basic Toggle Button (AS2)”

  1. kweku Says:

    Great. Thanks for this wonderful tute David, it will help me a lot.

  2. NSurveyor Says:

    It is possible to eliminate the toggle variable as well as the conditionals by just manipulating the _currentframe property, though it is harder to understand what’s happening at first glance.

    For the “toggling”, we need x=2->4, and x=4->2. The simplest mathematical expression that achieves this would be: 6-x. Other examples, include: x%3*2, (!(x/2-1)+1)*2.

    For the “rollover”, we need x=1->2, and x=3->4, which would simply be: x+1.

    For the “rollout”, we need x=2->1, and x=4->3, which again, is simply: x-1.

    Thus, our final code:

    btnToggle.stop();
    btnToggle.onRelease = function():Void {
    this.gotoAndStop(6-this._currentframe);
    }
    btnToggle.onRollOver = function():Void {
    this.gotoAndStop(this._currentframe+1);
    }
    btnToggle.onRollOut = function():Void {
    this.gotoAndStop(this._currentframe-1);
    }

    This works and all, BUT without a conditional, there is no place to handle when you click the button for each state. That could be remedied by placing the actual conditioned codes on frames 2 and 4, but that’s bad coding practice.

    The other way to deal with this, is to stick a conditional in, but that kills the whole point of this method somewhat… which is why this isn’t the best way to go about it! :)

    btnToggle.onRelease = function():Void {
    this.gotoAndStop(6-this._currentframe);
    if(this._currentframe == 2){
    //code
    }else {
    //other code
    }
    }
    btnToggle.onRollOver = function():Void {
    this.gotoAndStop(this._currentframe+1);
    }
    btnToggle.onRollOut = function():Void {
    this.gotoAndStop(this._currentframe-1);
    }

  3. David Stiller Says:

    NSurveyor,

    Good to hear from you! It’s been a while. Thanks for the notes. :)

  4. NSurveyor Says:

    Haha yeah, it’s been awhile. Strangely, I seem to take a few month break from Flash almost every year. Yesterday, I remembered about Flash and restarted my activity here, on the Adobe forums, and the Keyframer forum. Hopefully, I’ll stop hibernating and be using Flash year round!

  5. nab Says:

    hi david and guys
    well i need some help here
    i dont exactly know where to put it but here is my question
    there is a tutorial for a dynamic gallery on site i want to add a mp3 player to it which will also switch different play list as we click different categories on the menu
    any idea how to approach to it ?
    http://www.lukamaras.com/tutorials/actionscript/ultimate-dynamic-image-gallery-2.html how can i chnge the mp3 players play list based on xml when the user will chnge the categories in gallery thanx for help guys

  6. David Stiller Says:

    nab,

    Your question encompasses quite a few sub-questions, which leads to a general principle on approaching any goal in Flash (and programming in general): big things are made up of lots of little things. This maxim has helped me through so many projects over the years, I’ve lost count. The basic idea — and it’s not revolutionary, just surprisingly hard to remember sometimes — is simply to break down massive goals into smaller ones until the small ones make sense. As you approach each step, master that step in isolation, then gather your acquired knowledge toward the main destination.

    In this case, I would start with the gallery at lukamaras.com. Get that working solidly. Next, isolate the portion of that tutorial that responds to user clicks. Whatever handles the mouse clicks (an onRelease handler, presumably) can be instructed to perform other things as well. Whatever function is associated with advancing the gallery itself (or changing categories, or whatever) can make additional function calls — and those additional calls will be up to you.

    This is where I’d recommend you begin the “isolation” portion of your endeavor. Save your work and start a new FLA altogether. In the new FLA, you’ll create the MP3 player on its own, in isolation, away from the code of the gallery itself. Work your way toward playing a series of play lists. You might start with Array instances at first, then progress toward XML. There’s nothing especially magical about XML … it’s just a way to separate your list of songs from inside the SWF to the outside. One of the benefits is an easier update (you can change the song lists without recompiling the SWF) and one of the cons is complexity (you’ll have to instantiate the XML class and handle loading the document, responding to its loading, etc.).

    Any time a particular path on your trail gets too overgrown with complexity, break down your goal again. Maybe it’s time to create yet another FLA that deals with XML only. Practice creating XML objects and loading documents until you nail it. Eventually, you’ll build up to using XML in cahoots with the Sound class, which means eventually you’ll have an MP3 player that depends successfully on external play lists. Form there, you’ll be able to load new XML documents as desired, to play new songs, and that will be triggered by a function or method you’ve written. That function or method can be triggered from anywhere, including the gallery created from the lukamaras.com tutorial.

  7. nab Says:

    thnx a lot mate i already accomplished it :D

  8. David Stiller Says:

    nab,

    Terrific!

  9. Trey Says:

    i have a slide show movie made using the timeline. i put a previous play/pause and next button in the movie. I use your method and it works fine. there is an unexpected behavior that happens when the movie is paused/stopped. if the previous or next button is clicked while the movie is stopped the movie will begin to play again but the play/pause button will not toggle and the movie goes to the correct frame number. if i click play/pause again it works fine. the previous/next buttons work fine. oh yeah. the play/pause button is on the main timeline. the previous/next buttons are on the movie symbol. any thoughts? my actionscript is below.

    btnToggle.stop();
    btnToggle.toggled = false;

    btnToggle.onRelease = function():Void {
    this.toggled = !this.toggled; // this flip-flips the Boolean
    if (this.toggled) {
    this.gotoAndStop(2);
    tellTarget (”mainmovie”) {
    stop();
    }
    }
    else {
    this.gotoAndStop(1);
    tellTarget (”mainmovie”) {
    start();
    }
    }
    }

    __________________________________
    example previous next actionscript:
    on (release) {
    this.gotoAndPlay(386);
    }

    thanks for any and all help.
    trey

  10. Trey Says:

    i was wrong. the play state of the button stops working after the 1st time. to restart the movie i have to click the previous/next buttons. i can then stop the movie again with the play/pause button. but i can not use it to play the movie after i stop it.

    trey

  11. David Stiller Says:

    Trey,

    Based on your description, it sounds like you have at least three buttons: Prev, Next, and Pause/Play. If your Prev and Next buttons cause the main timeline to resume — effectively the same as untoggling the Pause/Play button — then it makes sense that your toggle will get out of sync. You’ll need to program your Prev and Next buttons not only to direct the timeline, but also to communicate with the Pause/Play button.

    Since you’re not using on() for Pause/Play (that is, btnToggle), I encourage you to do the same for Prev and Next. By keeping all your code in a single layer, it makes your ActionScript easier to find and maintain layer (see my “Museum Pieces” article). It looks like clicking the Next button (for example) needs to continue doing what it currently does, and in addition, set btnToggle’s toggled property to false and send it to frame 1 of its own timeline:

    btnNext.onRelease = function():Void {
      this._parent.gotoAndPlay(386);
      btnToggle.toggled = false;
      btnToggle.gotoAndStop(1);
    }

    Note the expression this._parent … you may have to adjust that path to suit, but the expression as shown assumes that your “mainmovie” target is the immediate parent of the Next button and that your Next button has the instance name btnNext. I’m not sure what “mainmovie” refers to, but you no longer need the dated tellTarget() function to instruct other objects. It’s often easier on the eye to simply use the same sort of dot notation to path to your objects as you’re already doing elsewhere in the code.

  12. Max Says:

    Great tutorial. Easy to understand and good use of grammar (which is hard to find these days!)

    cheers

  13. David Stiller Says:

    Max,

    Thanks!

Leave a Reply