AS3: SliderUI v1.5

View Example
View Documentation
Download Class & Example Files

I've updated the SliderUI class to add some more features. There is now a custom SliderUIEvent being dispatched, a setter method for the currentValue and percent properties which automatically moves the sliders to their appropriate spots when these are set, and a precision parameter passed into the constructor which allows you to round the currentValue off to the nearest "nth".

Actionscript:
  1. package com.reintroducing.ui
  2. {
  3.     import flash.display.Sprite;
  4.     import flash.display.Stage;
  5.     import flash.events.EventDispatcher;
  6.     import flash.events.MouseEvent;
  7.     import flash.events.TimerEvent;
  8.     import flash.geom.Rectangle;
  9.     import flash.utils.Timer;
  10.     import flash.utils.getQualifiedClassName;
  11.    
  12.     import com.reintroducing.events.SliderUIEvent
  13.  
  14.     /**
  15.      * The SliderUI is a class that allows you to quickly create sliders with tracks without the need to use components.
  16.      * There is a "percent" and a "currentValue" property that you can tap into to see what position the slider is at on the track.
  17.      * The SliderUI dispatches a couple of custom events that also contain these values as well as the slider and track display objects.
  18.      * <ul>
  19.      * <li>SliderUIEvent.ON_PRESS - Dispatched when the slider is pressed</li>
  20.      * <li>SliderUIEvent.ON_RELEASE - Dispatched when the slider is released</li>
  21.      * <li>SliderUIEvent.ON_UPDATE - Dispatched while the slider is dragged</li>
  22.      * <li>SliderUIEvent.ON_ENABLED - Dispatched when the slider is enabled</li>
  23.      * <li>SliderUIEvent.ON_DISABLED - Dispatched when the slider is disabled</li>
  24.      * </ul>
  25.      * </ p>
  26.      * Please note that if you are using the SliderUI on the "y" axis your track's registration point needs to be on the
  27.      * bottom (NOT the top) and the slider will go up to raise the value and down to lower it.  If you do not pay attention
  28.      * to this your slider will be "broken".
  29.      *
  30.     * @author Matt Przybylski [http://www.reintroducing.com]
  31.     * @version 1.5
  32.     */
  33.     public class SliderUI extends EventDispatcher
  34.     {
  35. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  36.  
  37.         private var _stage:Stage;
  38.         private var _track:Sprite;
  39.         private var _slider:Sprite;
  40.         private var _timer:Timer;
  41.         private var _percent:Number;
  42.         private var _lowVal:Number;
  43.         private var _highVal:Number;
  44.         private var _startVal:Number;
  45.         private var _currentVal:Number;
  46.         private var _range:Number;
  47.         private var _axis:String;
  48.         private var _changeProp:String;
  49.         private var _precision:int;
  50.        
  51. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  52.        
  53.        
  54.        
  55. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  56.    
  57.         /**
  58.          * Creates an instance of the SliderUI with the given parameters.  If the $startVal parameter is set to something
  59.          * higher than the $highVal or lower than the $lowVal parameter, the $startVal parameter is reset to one of those two values.
  60.          * If you do not set the $precision parameter, your current value will be rounded to the nearest whole number and the slider
  61.          * will snap into place at the appropriate position on the track.
  62.          *
  63.          * @param $stage The stage that the track and slider are sitting on
  64.          * @param $axis The axis that the slider will be used on
  65.          * @param $track The track to be used for the slider
  66.          * @param $slider The object that will function as the slider
  67.          * @param $lowVal A number representing the low value of the slider
  68.          * @param $highVal A number representing the high value of the slider
  69.          * @param $startVal A number representing the value the slider should start at (default: 0)
  70.          * @param $precision An integer representing the number of decimal places to round the current value to (default: 0)
  71.          *
  72.          * @return void
  73.          */
  74.         public function SliderUI($stage:Stage, $axis:String, $track:Sprite, $slider:Sprite, $lowVal:Number, $highVal:Number, $startVal:Number = 0, $precision:int = 0):void
  75.         {
  76.             this._stage = $stage;
  77.             this._axis = $axis;
  78.             this._track = $track;
  79.             this._slider = $slider;
  80.             this._lowVal = $lowVal;
  81.             this._highVal = $highVal;
  82.             this._startVal = $startVal;
  83.             this._precision = $precision;
  84.            
  85.             this._changeProp = (this._axis == "x") ? "width" : "height";
  86.             this._range = (Math.abs(this._lowVal) + this._highVal);
  87.             this._timer = new Timer(10);
  88.            
  89.             if (this._startVal <this._lowVal) this._startVal = this._lowVal;
  90.             if (this._startVal> this._highVal) this._startVal = this._highVal;
  91.            
  92.             this.manageRestingPosition(this._startVal);
  93.             this.initEvents();
  94.         }
  95.        
  96. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  97.        
  98.         // Initializes the slider and timer events.
  99.         private function initEvents():void
  100.         {
  101.             this._slider.buttonMode = true;
  102.            
  103.             this._slider.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
  104.             this._slider.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
  105.             this._timer.addEventListener(TimerEvent.TIMER, updateInfo);
  106.         }
  107.        
  108.         // manages the resting position depending on what value is passed in
  109.         private function manageRestingPosition($val:Number):void
  110.         {
  111.             if ($val <0)
  112.             {
  113.                 this._percent = (Math.abs(this._lowVal + Math.abs($val)) / this._range);
  114.             }
  115.             else
  116.             {
  117.                 this._percent = (Math.abs(this._lowVal - $val) / this._range);
  118.             }
  119.            
  120.             this._currentVal = this.roundToPrecision((this._lowVal + (this._range * this._percent)), this._precision);
  121.            
  122.             if (this._axis == "x")
  123.             {
  124.                 this._slider[this._axis] = (this._track[this._axis] + (this._percent * this._track[this._changeProp]));
  125.             }
  126.             else
  127.             {
  128.                 this._slider[this._axis] = (this._track[this._axis] - (this._percent * this._track[this._changeProp]));
  129.             }
  130.         }
  131.        
  132. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  133.    
  134.         /**
  135.          * Enables the controls of the SliderUI.
  136.          *
  137.          * @return void
  138.          */
  139.         public function enable():void
  140.         {
  141.             this.initEvents();
  142.            
  143.             this.dispatchEvent(new SliderUIEvent(SliderUIEvent.ON_ENABLED, this._percent, this._currentVal, this._slider, this._track));
  144.         }
  145.        
  146.         /**
  147.          * Disables the controls of the SliderUI.
  148.          *
  149.          * @return void
  150.          */
  151.         public function disable():void
  152.         {
  153.             this._slider.buttonMode = false;
  154.            
  155.             this._slider.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
  156.             this._slider.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
  157.             this._timer.removeEventListener(TimerEvent.TIMER, updateInfo);
  158.            
  159.             this.dispatchEvent(new SliderUIEvent(SliderUIEvent.ON_DISABLED, this._percent, this._currentVal, this._slider, this._track));
  160.         }
  161.        
  162.         /**
  163.          * Cleans up the SliderUI for garbage collection.
  164.          *
  165.          * @return void
  166.          */
  167.         public function destroy():void
  168.         {
  169.             this.disable();
  170.            
  171.             this._timer = null;
  172.         }
  173.    
  174. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  175.    
  176.         // Starts the dragging of the slider and starts the timer to dispatch percentage.
  177.         private function handleMouseDown($evt:MouseEvent):void
  178.         {
  179.             this.dispatchEvent(new SliderUIEvent(SliderUIEvent.ON_PRESS, this._percent, this._currentVal, this._slider, this._track));
  180.            
  181.             if (this._axis == "x")
  182.             {
  183.                 this._slider.startDrag(false, new Rectangle(this._track.x, this._slider.y, this._track.width, 0));
  184.             }
  185.             else
  186.             {
  187.                 this._slider.startDrag(false, new Rectangle(this._slider.x, this._track.y, 0, -this._track.height));
  188.             }
  189.            
  190.             this._timer.start();
  191.             this._stage.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp, false, 0, true);
  192.         }
  193.        
  194.         // Stops the slider dragging and timer.
  195.         private function handleMouseUp($evt:MouseEvent):void
  196.         {
  197.             this.dispatchEvent(new SliderUIEvent(SliderUIEvent.ON_RELEASE, this._percent, this._currentVal, this._slider, this._track));
  198.            
  199.             this._slider.stopDrag();
  200.             this._timer.reset();
  201.            
  202.             this.manageRestingPosition(this._currentVal);
  203.            
  204.             this._stage.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
  205.         }
  206.        
  207.         // Updates the info of the slider's position.
  208.         private function updateInfo($evt:TimerEvent):void
  209.         {
  210.             this._percent = Math.abs((this._slider[this._axis] - this._track[this._axis]) / this._track[this._changeProp]);
  211.             this._currentVal = this.roundToPrecision((this._lowVal + (this._range * this._percent)), this._precision);
  212.            
  213.             this.dispatchEvent(new SliderUIEvent(SliderUIEvent.ON_UPDATE, this._percent, this._currentVal, this._slider, this._track));
  214.         }
  215.  
  216. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  217.    
  218.         /**
  219.          * Returns the percentage of the slider's position on the track, between 0 and 1.
  220.          *
  221.          * @return Number
  222.          */
  223.         public function get percent():Number
  224.         {
  225.             return this._percent;
  226.         }
  227.        
  228.         /**
  229.          * Sets the slider's percentage according to the one provided and physically moves it to the corresponding position on the track.
  230.          *
  231.          * @param $val The value to set the percentage to.
  232.          *
  233.          * @return void
  234.          */
  235.         public function set percent($val:Number):void
  236.         {
  237.             this._percent = $val;
  238.             
  239.             this.manageRestingPosition(this._percent);
  240.         }
  241.        
  242.         /**
  243.          * Returns the current value of the slider's position on the track.
  244.          *
  245.          * @return Number
  246.          */
  247.         public function get currentValue():Number
  248.         {
  249.             return this._currentVal;
  250.         }
  251.        
  252.         /**
  253.          * Sets the slider's current value according to the one provided and physically moves it to the corresponding position on the track.
  254.          *
  255.          * @param $val The value to set the currentValue to.
  256.          *
  257.          * @return void
  258.          */
  259.         public function set currentValue($val:Number):void
  260.         {
  261.             this._currentVal = $val;
  262.             
  263.             this.manageRestingPosition(this._currentVal);
  264.         }
  265.    
  266. //- HELPERS -----------------------------------------------------------------------------------------------
  267.    
  268.         private function roundToPrecision($num:Number, $precision:int = 0):Number
  269.         {
  270.             var decimalPlaces:Number = Math.pow(10, $precision);
  271.             return (Math.round(decimalPlaces * $num) / decimalPlaces);
  272.         }
  273.        
  274.         override public function toString():String
  275.         {
  276.             return getQualifiedClassName(this);
  277.         }
  278.    
  279. //- END CLASS ---------------------------------------------------------------------------------------------
  280.     }
  281. }

I've updated the example as well to show the usage of the new events. Please view the documentation for details on all the changes.

If you found this post useful, please consider leaving a comment, subscribing to the feed, or making a small donation.

23 Comments

Thanks for posting this!

Simple, straightforward and small. It's sort of a code haiku. 🙂

I am considering setting up a snap-to-value option. I'll send you the code if I succeed.

mcubebrooklyn,
if i'm not mistaken, i think what you're trying to achieve is already implemented. it snaps to the value you put in with the precision param in the constructor.

Hey, great tool here, thanks for posting it. However, I have run into a small problem that I have searched and searched for but cannot solve.

It appears that when I create the slider sprites programmatically, the thumb sprite is movable beyond the boundary of the track. (By the height of the thumb sprite.) Here is my code:

-----------------------------------------------------
import com.reintroducing.ui.SliderUI;
import com.reintroducing.events.SliderUIEvent;

// SLIDER TRACK
var volTrack:Sprite = new Sprite();
volTrack.graphics.lineStyle(1,0xAAAAAA);
volTrack.graphics.beginFill(0x222222);
volTrack.graphics.drawRect(0,0,20,-100);
volTrack.graphics.endFill();
volTrack.x = stage.stageWidth / 2;
volTrack.y = stage.stageHeight / 2;

// SLIDER BOX
var volSlider:Sprite = new Sprite();
volSlider.graphics.beginFill(0xCCCCCC);
volSlider.graphics.drawRect(0,0,19,-10);
volSlider.graphics.endFill();
volSlider.x = (stage.stageWidth / 2) + 1;
//volSlider.y = (stage.stageHeight / 2) - 10;

addChild(volTrack);
addChild(volSlider);

// CONFIGURE SLIDERS
var volSliderObj:SliderUI = new SliderUI(stage, "y", volTrack, volSlider, 0, 100, 75);
--------------------------------------------------

Am I missing some obvious?

Thanks for any help!

@fodder: The SliderUI is designed to go from the middle of the slider, not an edge, on the track. therefore you'd want to move your y axis point in the drawRect function for volSlider up a bit, as shown here:

Actionscript:
  1. import com.reintroducing.ui.SliderUI;
  2. import com.reintroducing.events.SliderUIEvent;
  3.  
  4. // SLIDER TRACK
  5. var volTrack:Sprite = new Sprite();
  6. volTrack.graphics.lineStyle(1,0xAAAAAA);
  7. volTrack.graphics.beginFill(0x222222);
  8. volTrack.graphics.drawRect(0,0,20,-100);
  9. volTrack.graphics.endFill();
  10. volTrack.x = stage.stageWidth * .5;
  11. volTrack.y = stage.stageHeight * .5;
  12.  
  13. // SLIDER BOX
  14. var volSlider:Sprite = new Sprite();
  15. volSlider.graphics.beginFill(0xCCCCCC);
  16. volSlider.graphics.drawRect(0,-5,19,10);
  17. volSlider.graphics.endFill();
  18. volSlider.x = (stage.stageWidth * .5) + 1;
  19. volSlider.y = (stage.stageHeight * .5);
  20.  
  21. addChild(volTrack);
  22. addChild(volSlider);
  23.  
  24. // CONFIGURE SLIDERS
  25. var volSliderObj:SliderUI = new SliderUI(stage, "y", volTrack, volSlider, 0, 100, 75);

hope this helps.

@Matt:

Thanks so much for the help! I was assuming that I was just missing a way to specify padding or bounds on each slider.

Your explanation pointed me in the right direction and now I am just creating a separate track (set to alpha = 0) that I can adjust the dimensions to make the slider bounds fit inside my background.

Thanks again!

[...] Please use SliderUI v1.51 for the latest and [...]

Very Great! Thanks for sharing!

This class really is great. Thanks for creating it.

I am somewhat new to as3 so I apologize if this is a newb question, but I have an issue regarding the stage parameter.

I have a working volume slider using version 1.51.
When I load the swf with the slider into another, I get the "Cannot access a property or method of a null object reference" on the SliderUI/handleMouseDown() and SliderUI/handleMouseUp() methods.

Now the slider still seems to operate properly, but I was wondering if there was something other than 'stage' I should be sending into the constructor in these cases to avoid that output error.

Thanks again. Awesome class!

@Dan: It sounds like the stage is not yet initialized before creating your instance of the sliderUI. Make sure that wherever you're adding the instance, that class (if it extends a display object of some type) is being initialized on ADDED_TO_STAGE or something similar. hope that helps.

Yes. That helped tremendously.

Thank you, Matt. Much appreciated.

np, glad i could help!

[...] Es gibt die Schieberegler-Klasse auch in der Version SliderUI v1.5. Die neue Version beinhaltet u.A. ein Flash-CustomEvent, was z.B. bei unserer Anwendung zum Einsatz [...]

Thanks for posting this! We adapted the SliderUI v1.51 to work within the GestureWorks AS3 framework for a multitouch application (see previous pingback post in German). Works great!

Hi Matt,

Thanks a lot for your very helpful slider class.
Unfortunately, I am not quite sure how to use the "set method" in order to set the slider to a desired position (e.g. as the result of a button press).
Any help would be greatly appreciated.

Thanks,

Tobi

@Tobias: All you have to do is set slider.currentValue = 2; or whatever number that is in between your range and it'll move there (do that on the click of your button).

Thanks a lot Matt for your very quick reply!

It works (of course) 🙂

Hi, nice class you've written there.
Perfect for a project I am using, but I have this question.
I know my way around flash, yet classes is still a bit misty for me.

On stage i have a movieclip called fadeBox,
inside of there resided the slider which works perfectly
but i'd like to alter based on the value a different movieclip called "photoHolder" this one is at the same level as the slider.

Inside your class in the updateInfo part, i am trying to set the alpha of the movieclip "photoholder" but i can't seem to target it.
fe.
MovieClip(parent).photoholder.alpha = this._currentValue;

alas it says error 1120: Access of undefined property parent. Inside your class i referenced both movieclips fadeBox & photoholder.

Thanks if you could shed a light upon this.

@tom: you don't want to be adding code to the class at all, you would be doing that outside of the class wherever you're using it.

nice class.... I found it a little strange you did not have setters on the values... so that you could set however you see fit...
regardless...
thanks.

@Michael: Not sure what you're referring to, you can set the currentValue and the percent which are really the only two values you'd want to set after the initial setup, I presume.

Hi Matt, this is a pretty nice class you have here and it saved me a lot of work. There were a few changes I made to make it a bit easier for me to use, which you might consider for the next version.

1) I added two public static consts to the SliderUI class for X_AXIS and Y_AXIS for use as typo-guards

2) I removed $stage from the constructor and added
this._stage = _slider.stage;
to the handleMouseDown listener function. _slider really shouldn't be receiving mouse events unless it's added to the stage: The only instance in which this would be occurring is if the user is manually making and sending events to the listener, in which case they deserve what they get 😉
Now the slider class can be instantiated painlessly even before a handle to the stage is available.

3) I added getter functions for the slider and track so that
4) I could remake the constructor of the event class so it just takes the identity of the dispatching SliderUI. Now instead of currentVal, percentage, etcetera it just has the public member 'dispatchedBy', and any pertinent information can still be easily accessed as in 'e.dispatchedBy.currentVal'
The reason I made this final change is so that I could make a bunch of sliders in a vector and then give them all one listener and an appropriate switch statement. It's possible this could be achieved through the Event.target or Event.currentTarget properties, but I honestly can't find a good explanation for how those really work, and this seemed simpler.

Hi there! This post could not be written any better! Reading this post reminds me of my previous room mate!
He always kept chatting about this. I will forward
this post to him. Fairly certain he will have a good read.
Thank you for sharing!

Leave a comment

(required)

(required)