Easy Movie Clip Buttons Part 3 of 3: Defining Button States

In Part 1 I demonstrated how to dynamically populate existing movie clip buttons. in Part 2 I showed you how to dynamically place the button on screen. In the third and final installment, I’ll show you how to code your clips to behave like buttons. Using movie clips rather than buttons gives me the ability to code as many states as I want. My buttons will have four states: Active, Over, Down, and Selected. Download the sample to get started. Here’s what we’ll be creating:

Let's start by double-clicking the button in the library to bring it up in enter mode. There four sections defined, each representing a state. This could have been done in four frames but I wanted the labels to be visible. You'll notice that my 'button text' layer extends across all states. This is because the button text will remain the same. If I added a keyframe in each state for the button text, I would have to redefine it every time the state changed.

I placed no ActionScript inside the movie clip button, opting instead to place all of my code in the main timeline. The only code I needed to add when placing the button on the stage was the stop(); on line 14 which places each button as 'active':

this[container_mc].button_mc.stop();

Active is the default state of my button. The Over section will appear when the user moves the mouse over the button. Down is for when the user has pressed the mouse button but hasn't yet released it. Selected is show the user which option is current. Obviously, in this specific example, the value in the fullMonth_txt text field will give that information away but most of the time it won't be so obvious.

Labeling the frames that start each state section not only makes it easy to find the object states at a glance when viewing the movie clip, but also makes it easy to see what the code is doing. Now that I have a different look for each state, I'll code the functions for each section.

First I start by defining a variable named selectedButton. Because I don't want the selected button to change to any other state unless another button is clicked, I need a variable to keep track of which one is selected.

var selectedButton:MovieClip;

Now the only thing I have left to do is code the buttons, which takes very little code. First, a slight modification to the onRelease definition:

this[container_mc].button_mc.onRelease = function() {
fullMonth_txt.text = this.monthName;
if(selectedButton && selectedButton != this) {
selectedButton.gotoAndStop("active");
};
selectedButton = this;
this.gotoAndStop("selected");
};

Because I start without a selected button, selectedButton starts with a value of undefined. The first thing I added to each state function then is a check to see whether it's been defined. If so, I then need to make sure that I don't change the state if of the currently-selected button.

So, in the case of onRelease, providing that the button the user clicks is not the currently selected button, the function will first change the state of the currently-selected button back to active (unselected), then it redefines the selectedButton variable to reflect the new selection, and finally it changes the newly selected button to the ‘selecteds frame.

If that seems pretty easy, you'll be happy to know that the rest of the state functions are even easier because we don't even have to worry about a variable to change or whether a button has been selected yet. We simply have to change the movie clip button's frame to reflect the new state. Here are the rest of the functions:

this[container_mc].button_mc.onRollOver = this[container_mc].button_mc.onDragOver = function() {
if (selectedButton != this) {
this.gotoAndStop("over");
};
};

this[container_mc].button_mc.onRollOut = this[container_mc].button_mc.onDragOut = function() {
if (selectedButton != this) {
this.gotoAndStop("active");
};
};

this[container_mc].button_mc.onPress = function(){
if (selectedButton != this) {
this.gotoAndStop("down");
};
};

The one piece of code here that you may find mildy tricky is the dual-definitions for rollOver/dragOver and rollOut/dragOut. Basically, I'm just using ActionScript to define the same functions for multiple events. It's the same as writing a = b = c to make a and b equal to the value of c. The only difference in the last three functions is the frame the movie clip moves to. Other than that, they're identical.

And that's all there is to it. You now know how to dynamically place and code multiple movie clip buttons with multiple states in only 50 lines of code.

-rG

7 thoughts on “Easy Movie Clip Buttons Part 3 of 3: Defining Button States

  1. Excellent tutorial! I finally understood arrays and how they work. It’s amazing how long I went without using them!

    I don’t know if you are familiar with TweenMax, a custom tweening class. The point is, I’m trying to use tweenMax instead of defining the states of the button to change it’s appearance, making the buttons totally dynamic. My problem is that after selecting one button, if I select a second one, the first buttons appearance does not change back to active, here’s my code (i changed some variable names to better suit my project, but it’s basically the same as the last example)

    stop();
    //tween
    import gs.*;
    import gs.easing.*;
    //buttons array
    var labels_array:Array = new Array({label_txt:”Perfil”, ex_mc_name:”profileM”}, {label_txt:”Proyectos”, ex_mc_name:”projectsM”}, {label_txt:”Contacto”, ex_mc_name:”contactM”});
    var initX:Number = 0;//row starting X coord
    var nextX:Number = initX;//first X coord for button
    var nextY:Number = 0;//first Y coord for button
    var wrapY:Number = 1;//will start new row after this many buttons
    var selectedButton:MovieClip;

    var container_mc:String = “”;
    for (var i:Number = 0; i<labels_array.length; i++) {
    container_mc = “cont”+i;
    this.createEmptyMovieClip(container_mc,this.getNextHighestDepth());
    this[container_mc].attachMovie(“button_mc”,”button_mc”,this.getNextHighestDepth,{_x:nextX, _y:nextY});
    this[container_mc].button_mc.name_txt.text = labels_array[i].label_txt;
    this[container_mc].button_mc.sectionToLoad = labels_array[i].ex_mc_name+”.swf”;
    //Selected
    this[container_mc].button_mc.onRelease = function() {
    if (selectedButton && selectedButton != this) {
    TweenMax.to(this,.5,{tint:0xffffff, ease:Cubic.easeOut});
    }
    selectedButton = this;
    TweenMax.to(this,.5,{tint:0x487CA9, ease:Cubic.easeOut});
    };
    //Over
    this[container_mc].button_mc.onRollOver = this[container_mc].button_mc.onDragOver=function () {
    if (selectedButton != this) {
    TweenMax.to(this,.5,{tint:0x65C5DF, ease:Cubic.easeOut});
    }
    };
    //Active
    this[container_mc].button_mc.onRollOut = this[container_mc].button_mc.onDragOut=function () {
    if (selectedButton != this) {
    TweenMax.to(this,.5,{tint:0xffffff, ease:Cubic.easeOut});
    }
    };
    //Down
    this[container_mc].button_mc.onPress = function() {
    if (selectedButton != this) {
    TweenMax.to(this,.5,{tint:0x487CA9, ease:Cubic.easeOut});
    }
    };

    if (i == (wrapY-1)) {
    wrapY += 1;//if there were more than two rows this would start new row after every 6 buttons
    //line next button up under first button
    nextX = initX;
    nextY += 20;
    }
    /*else {
    //set next button to the right of previous button
    nextX += 57;
    }*/

    }
    button_mc contains the dynamic text field only.

    Hope you can help out, thx!

  2. Excellent tutorial, how could I do the same thing in AS3? My problem is that i have 3 buttons which execute different actions so I had to add a listener to each button which call a different function(even if the over and out listeners are the same for all buttons)

  3. I have another question, hope you can answer. How will I start with a selected button? I have tried to define the value of the selectedButton variable, but I guess I’m doinf something wrong

Comments are closed.