Easy Custom Scrollbar Class for TextFields (AS2) – taterboy
September 17th, 2008 | Filed under: Design, Flash AS2 to AS3

Here is the twin brother of the Easy Scrollbar MovieClip Class that works with TextFields. It does not require the masking and is perfect for Input TextFields. It has all the features of the MovieClip version except for easing. TextFields scroll one line at a time which is not very smooth.

Some of the features include:
Auto On/Off - you may need a scrolling clip that could change in size as dynamic content is displayed or entered. When the scroll bar is not needed, it will turn itself off and back on when it is needed. Or you can manually turn it on and with your code.

Scroll Bar Resizing - To simulate the function of desktop applications, the scroll bar will automatically scale depending on the amount of scroll, This feature can be turned on or off.

Auto Resize - Say you have a project that needs multiple scroll bars. One 150 px tall, the other 500 px tall. With this class you can build one set of artwork and the class will automatically adjust the bottom button, scroll background, scrollbar scroll area to fit the needed size.

Down Button Flip - This will not change the world, but if you have an Up Button that is exactly like the bottom button just flipped vertically. The class will compensate for this, saving a few minutes of development time and a few kilobytes.

Scroll Background Hiding and resizing - Many scroll bars have a background track, you may want it visible when the scroll bars are disabled as a visual place holder. This feature can be turned on or off.

Works without a scroll bar or without up and down buttons.

Button Type Effects - Even though the buttons and scrollbars are made with movieClips, sample code and calls are provided to give them button type effects on rollOver, rollOut, press and release.

Usage may seem a little complex at first, but if you like designing and using custom scroll bars and buttons, it is totally worth it.

1. Create all your scroll objects, they should be converted to MovieClips.
(upButton, DownButton, ScrollBar, and ScrollBkg)

2. Place the up and down buttons, scroll bar, and scroll background into a new movieClip.
(ScrollObject)

3. Align the top button and scrollbar to it’s starting position.

4. Apply the class, this is the most complex part.

var scrollSet:HDScrollText = HDScrollText(ScrollObject,ScrollMovieClip,UpButton,DownButton,ScrollBar,ScrollBarResize,ScrollBkg,ScrollBkgHide,DownButtonFlip,ResizeScrollObjects,AutoOn);

This is where you assign all the MovieClips and enable any of the features. Other than the 6 MovieClips that the class points to, the other 5 arguments are features to enable or disable.

ScrollBarResize: Boolean
ScrollBkgHide: Boolean
DownButtonFlip: Boolean
ResizeScrollObjects: Boolean
AutoOn: Boolean

Once it is enabled, it can manage itself or you can manage it manually with a method like so:
scrollSet.ScrollStatus(true); or scrollSet.ScrollStatus(false);

When you are done with everything, you can strip all the code out by calling scrollSet.killScrollBar();

import mx.utils.Delegate;
class com.hdi.util.HDScrollText{
	/*
	HDScrollText oringinally created 11/2005 by Todd Williams and HD Interactive.
	©2005 - 2008 HD Interactive & Taterboy, Inc.
	version: 2.0
 
	Compatibility:  Action Script 2, Flash Player 7 and higher.
	Purpose:
	To Build a scrollbar class that is truly portable and can be applied to custom artwork
	of any size and shape. This class wraps the graphics instead of graphics wrapping the code.
	This gives the designer complete control over look and feel. One of the major features
	needed was to have one set of scroll objects to be 	used in multiple instances and allow
	them to automatically conform to different scrolling needs. One set of scroll objects can
	control a scroll window that is 200 pixels tall or 600 pixels tall on the same stage at the 
	same time.
 
	Features:
		1. Automatically arranges scroll objects so that one set scrollbar objects can be used in multiple 
		    instances with different sized scrolling windows.
		2. Resizing scroll bar similar to OS and desktop application scroll bar behavior.
		3. Code Wraps to custom artwork instead of skinning a preexisting component.
		4. Auto on and off. The scroll bar is smart enough to know when it is needed or not.
		5. Code provided to build button type effects into MovieClip buttons and scrollbar.
		6. Have multiple scrolling objects visible and functioning on the same stage at a time.
 
 
	Preparation:
	To prepare graphic objects for use with HDScrollMC, you will need to create 7 MovieClips.
	MC 1. The MovieClip to be scrolled:
		 For scrolling text, create a TextField inside of a MovieClip, fill it with text manually, 
		 or use dynamic text and the TextField.autoSize = true;
 
	MC 2. Container for Scroll Objects: To make it possible to have multiple scrolling objects on the
	stage at the same time, it is best to have at least the scrollbar and scroll button objects in a
	container, the mask and MC to be scrolled can also be in this container if desired.
 
	MC 3 & 4.  Scroll buttons UP and Down. These buttons are not required if a scrollbar only design is 
		needed. Scroll buttons can be movieClips or buttons. Code for rollover and press events will be 		sent to each button. If you want to use a MovieClip, disperse your button states on frames as you 		would a button and add a stop action to the first frame. Also the down button and be a vertically 		flipped instance if the top button if the artwork allows for this.
 
		The scroll buttons receive the following method calls from the class, use the method below for 
		MovieClips with button type effects.
		btnEvent(1); roll on
		btnEvent(0); roll out
		btnEvent(2); mouse down
		btnEvent(1); mouse up
		Sample:
		function btnEvent(val){
			if(val == 1){
				//roll on / release
			}
			else if(val == 2){
				//press
			}
			else{
				//roll out
			}
		}
		Super Simple Sample:
		function btnEvent(val){
			gotoAndStop(val+1);
		}
 
	MC 5. Scroll Bar: Must be a MovieClip and like the buttons, code will be sent for rollover and press events.
		A scrollbar is not required if a button only design is required. For the scroll bar has a resize feature 
		with two modes. The scroll bar will resize bases on the amount of scroll and the size of the scroll 
		area, similar to OS scroll bars. Mode 1 is the scrollbar MovieClip resizes the whole MovieClip. Some 
		graphic distortion or stretching may occur. You can set the scale9Grid to this MovieClip prior to 
		enabling this class. Mode 2 uses three MovieClips within the Scroll Bar to represent the top, middle 
		and bottom of the scroll bar, the middle will stretched will the top and bottom MovieClips will retain 
		their graphic integrity. To use this option divide the Scrollbar into three horizontal slices. Create 
		MovieClip instances named scrollbBarTop, scrollBarBot, and scrollBarMid.
 
		The scrollbar receives the following method calls from the class, use the method below for 
		MovieClips with button type effects.
 
		barEvent(1); roll on
		barEvent(0); roll out
		barEvent(2); mouse down
		barEvent(1); mouse up
		Sample:
		function barEvent(val){
			if(val == 1){
				//roll on / release
			}
			else if(val == 2){
				//press
			}
			else{
				//roll out
			}
		}
		Super Simple Sample:
		function btnEvent(val){
			gotoAndStop(val+1);
		}
 
	MC 6. Scroll background, Must be a MovieClip,  will span the entire size of the scroll area
		if the class is set to resize the objects. This MovieClip can be used to have a decorative
		track for the scroll area and can be set to vanish or remain when the scrollbar is enabled
		or disabled. This object is not required.
 
	Usage:
		Place the class folder in the working directory next to the fla you are using;
		add import com.hdi.util.HDScrollText; to the actions panel before the code below.
 
	HDScrollText(ScrollObject,TextField,UpButton,DownButton,ScrollBar,
	ScrollBarResize,ScrollBkg,ScrollBkgHide,DownButtonFlip,ResizeScrollObjects,AutoOn);
 
	I know there are a lot of arguments, and the descriptions/Usage are as follows:
	ScrollObject - (required) target of scroll object container, MC 3 from the preparation list.
	ScrollMovieClip - (required) target of MovieClip to be scrolled, MC 1 from preparation list.
	UpButton - target or null, to Up Button MovieClip or Button. MC 4 & 5 from preparation list.
	DownButton - target  or null, to Down Button MovieClip or Button. MC 4 & 5 from preparation list.
	ScrollBar - target or null, to Scroll Bar MovieClip. MC 6 from preparation list.
	ScrollBarResize - Boolean: true or false, To enable scroll bar resizing depending on scroll amount.
	ScrollBkg - target or null, to scroll background graphic.
	ScrollBkgHide - Boolean: true or false, default behavior is to hide scroll background and scroll objects;
	DownButtonFlip - Boolean: true or false, If the down button is an instance of the up button that is
		vertically flipped.
	ResizeScrollObjects - Boolean: true or false, when scroll bar loads, it calculates the size of the mask, 
		buttons, scrollbars and distributes them to the appropriate height and coordinates. This allows 
		different instances of a set of scroll objects to be used with different sized scrolling Objects. 
	AutoOn - Boolean: true or false, Turns control of turning the scroll bar objects on and off to the class.
		If the scrolling MovieClip changes in size the class will automatically enable or disable the
		scroll objects.
 
 
	Other methods and properties:
 
	scrollStatus:  property (Boolean) - tells if scrolling is enabled or disabled.
	setScrollStatus: Function - manually enables/disables scrolling.
	killScrollBar: Function - permanently disables the scrollbar and removes all listeners and events.
 
	Tips:
	1. For best performance, zero out  x and y coordinates to whole numbers on all MovieClips. 	
	Also try to build artwork with artwork rounded to the nearest whole pixel. This stops a lot
	of the little glitches 	that can appear when a user interacts with the scrolling objects.
 
	2. If you do not want you scroll objects to flash on then off on load, set the scroll Object
	Container's (MC 3) 	alpha property to 0. The class will automatically set it to 100 when enabled.
 
	3. By default the class uses the scroll background  and/or the up button to align and distribute
	the rest of the 	objects. You should align the top button and the top of the scroll background.
	The top of the scrollbar 	should be aligned to the button of the top button. These coordinates
	are used as starting points for all of 	the scroll objects and will return them to these
	positions when the scroll bar is reset.
 
	*/
private var scrollObj:Object; //scroll MovieClip containing up button, down button, scrollbar, background.
	private var tClip:Object; //TextField to be scrolled.
	private var tMask:Object; //Mask for the Text MovieClip, must be a MovieClip.
	private var dwnBtn:Object; //Down button, should be movieClip or button.
	private var upBtn:Object; //Down button, should be movieClip or button.
	private var scrollBar:Object; //MovieClip to do the scrolling.
	private var barAutoSize:Boolean; //Resizes the scroll bar to the scroll amount.
	private var scrollBkg:Object; //Background behind scrollButtons and scrollBar.
	private var scrollBkgHide:Boolean; //When scroll objects are not on, ScrollBkg is can be visible or not.
	private var flipDwnButton:Boolean; // If you have flipped the upBtn to make the dwnBtn. Used for autoResize.
	private var resizeObj:Boolean; // Resizes scroll objects to match the mask size and location.
	private var autoOn:Boolean; //Let's the scroll object control if the scrollBar is on or off, depending on the size of the text box.
	private var easeIn:Number; // Amount of delay for scrolling text to ease into possition.
	private var scrollYPos:Number;
	public var scrollStatus:Boolean; //Scrollbar is On or Off.
	private var inc:Number;
	private var resetAllSizes:Function;
	function HDScrollText(targObj,tclip,upbtn,dwnbtn,sbar,barsize,sbkg,sbkgHide,flip,reSize,auto){
		scrollObj = targObj;
		tClip = tclip;
		tMask = tclip;
		upBtn = upbtn;
		dwnBtn = dwnbtn;
		scrollBar = sbar;
		barAutoSize = barsize;
		scrollBkg = sbkg;
		scrollBkgHide = sbkgHide;
		flipDwnButton = flip;
		resizeObj = reSize;
		autoOn = auto;
		easeIn = 0;
 
		scrollYPos = tClip.scroll;
		if(tClip.maxscroll < 2){
			scrollStatus = false;
			if(scrollBkgHide && scrollBkg){
				scrollBkg._visible = false;
			}
		}
		else{
			scrollStatus = true;
		}
 
		var testConfig:Boolean = true;
		if(scrollObj == null || scrollObj == undefined){
			trace("ERROR: ScrollObject (arg 0) needs to be a valid MovieClip ");
			testConfig = false;
		}
		if(tMask == null || tMask == undefined){
			trace("ERROR: MaskMC (arg 2) needs to be a valid MovieClip - please mask the scrolling object with a named instance of a MovieClip");
			testConfig = false;
		}
		if((scrollBar == null || scrollBar == undefined) && (upBtn == null || upBtn == undefined) && (dwnBtn == null || dwnBtn == undefined)){
			trace("ERROR: Very funny, you need at least 1 control object (scrollBar, upBtn or dwnBtn) assigned to initiate scrolling");
			testConfig = false;
		}
		if(testConfig){
			init();
		}
	}
	public function setScrollStatus(val,overRide){
		scrollStatus = val;
		scrollObj.stat = val;
		scrollObj.yPos = scrollObj.starty;
		tClip.scroll = scrollObj.starty;
		scrollBar._y = scrollObj.bary;
		setSizes();
		if(val){
			upBtn._visible = true;
			dwnBtn._visible = true;
			scrollBar._visible = true;
			scrollBkg._visible = true;
		}
		else{
			upBtn._visible = false;
			dwnBtn._visible = false;
			scrollBar._visible = false;
			if(scrollBkgHide){
				scrollBkg._visible = false;
			}
		}
	}
	public function killScrollBar(){
		tClip.scroll = scrollObj.starty;
		scrollBar._y = scrollObj.bary;
		scrollObj.yPos = scrollObj.starty;
		upBtn._visible = false;
		dwnBtn._visible = false;
		scrollBar._visible = false;
		delete scrollObj.onEnterFrame;
		delete scrollBar.onMouseUp;
		delete scrollBar.onMouseDown;
		delete scrollBar.onMouseMove;
		delete upBtn.onMouseUp;
		delete upBtn.onMouseDown;
		delete dwnBtn.onMouseUp;
		delete dwnBtn.onMouseDown;
		delete upBtn.onRollOut;
		delete upBtn.onRollOver;
		delete dwnBtn.onRollOut;
		delete dwnBtn.onRollOver;
		delete scrollBar.onRollOut;
		delete scrollBar.onRollOver;
		//Mouse.removeListener(scrollObj.myWheel);
	}
	private function setSizes(){
		if(tClip.scroll < scrollObj.starty){
			if(tClip.scroll <= tClip.maxscroll){
				scrollObj.yPos = scrollObj.starty;
			}
			else{
				scrollObj.yPos = tClip.maxscroll;
			}
		}
		else if(tClip.scroll > scrollObj.starty){
			scrollObj.yPos = scrollObj.starty;
		}
 
		tClip.scroll = scrollObj.yPos;
 
		if(barAutoSize == true){
		//setup dynamic scrollbar height.
			var sbHeight:Number;
			if(tClip._height > scrollObj.maskh){
				sbHeight = Math.floor((tClip._height / tClip.textHeight) * scrollObj.bardist);
			}
			else{
				//sbHeight = 
			}
			if(sbHeight < 20){
				sbHeight = 20;
			}
			if(scrollBar.scrollbBarTop._name == undefined){
 
				scrollBar._height = sbHeight;
			}
			else{
				scrollBar.sheight = sbHeight
				scrollBar.scrollBarMid._height = scrollBar.sheight - (scrollBar.scrollbBarTop._height + scrollBar.scrollbBarTop._height);
				scrollBar.scrollbBarTop._y = scrollBar.scrollBarMid._height + scrollBar.scrollBarMid._y;
			}
 
		}
 
		scrollObj.bht = Math.ceil(scrollBar._height);
		scrollObj.barslack = (scrollObj.boty - scrollObj.topy) - scrollObj.bht;
		scrollObj.scrolldist = tClip.maxscroll;
		scrollObj.scrollspeed = 1;
		scrollObj.yspeed = tMask._height/10;//16;
		scrollObj.upscroll = 0;
		scrollObj.dwnscroll = 0;
		scrollBar._y = (((tClip.scroll-1)/(tClip.maxscroll-1)) * (scrollObj.barslack)) + scrollObj.topy;
	}
	private function setCoors(){
		tMask._height = Math.ceil(tMask._height);
		scrollObj.maskh = tMask._height;
		if(resizeObj){
			flipDwnButton == true? dwnBtn._y = Math.round(tMask._height): dwnBtn._y = Math.round((tMask._height) - dwnBtn._height);
			//flipDwnButton == true? dwnBtn._y = Math.round(tMask._height + tMask._y): dwnBtn._y = Math.round((tMask._height + tMask._y) - dwnBtn._height);
 
			if(scrollBkg != null){
				upBtn != null ? scrollBkg._height = scrollObj.maskh: scrollBkg._height = scrollObj.maskh;
			}
 
		}
		upBtn._y = Math.floor(upBtn._y);
		scrollObj.tht = Math.ceil(tClip._height);
		scrollObj.starty = tClip.scroll;
		scrollObj.barx = scrollBar._x;
		scrollObj.bary = scrollBar._y;
		if(upBtn != null){
			scrollObj.topy = Math.round(upBtn._y + upBtn._height);
			flipDwnButton == true? scrollObj.boty = Math.round(dwnBtn._y - dwnBtn._height): scrollObj.boty = Math.round(dwnBtn._y);
		}
		else{
			scrollObj.topy = Math.round(scrollBar._y);
			scrollObj.boty = Math.round(scrollBar._y + tMask._height);
		}
		scrollObj.bardist = (scrollObj.boty - scrollObj.topy);
		setSizes();
	}
 
	private function init(){
		setCoors();
		if(scrollStatus == false){
			upBtn._visible = false;
			dwnBtn._visible = false;
			scrollBar._visible = false;
		}
		else{
			upBtn._visible = true;
			dwnBtn._visible = true;
			scrollBar._visible = true;
		}
		scrollObj._alpha = 100;
		scrollObj.objectRef = this;
		scrollBar.objectRef = this;
		upBtn.objectRef = this;
		dwnBtn.objectRef = this;
		var scrollParent:Object = scrollObj;
		var scrollTextField:Object = tClip;
 
		scrollObj.stat = scrollStatus;
		scrollObj.yPos = scrollYPos;
 
		if(resizeObj){
			resetAllSizes = setCoors;//setSizes;
		}
 
		scrollBar.onMouseDown = function(){
			if(this._visible == true){
				if(this.hitTest(_root._xmouse, _root._ymouse, false)){
					this.barEvent(2);
					scrollParent.scrollchk = true;
					this.startDrag(false,scrollParent.barx,scrollParent.topy,scrollParent.barx,scrollParent.boty - scrollParent.bht);
					this.onMouseMove = function(){
						if(scrollParent.scrollchk == true){
							scrollParent.yPos = Math.round(scrollTextField.maxscroll * ((this._y - scrollParent.topy)  /scrollParent.barslack));
						}
 
					}
				}
			}
			else{
			}
		}
		scrollBar.onMouseUp = function(){
			scrollParent.scrollchk = false;
			if(this.hitTest(_root._xmouse, _root._ymouse, false)){
				this.barEvent(1);
			}
			this.stopDrag();
		}
		scrollBar.onRollOut = function(){
			this.barEvent(0);
		}
		scrollBar.onRollOver = function(){
			this.barEvent(1);
		}
		upBtn.onMouseDown = function(){
			if(this._visible == true){
				if(this.hitTest(_root._xmouse, _root._ymouse, false)){
					this.btnEvent(2);
					scrollParent.upscroll = 1;
				}
			}
		}
		upBtn.onMouseUp = function(){
			if(this.hitTest(_root._xmouse, _root._ymouse, false)){
				this.btnEvent(1);
			}
			else{
				this.btnEvent(0);
			}
			scrollParent.upscroll = 0;
		}
		upBtn.onRollOut = function(){
			this.btnEvent(0);
		}
		upBtn.onRollOver = function(){
			this.btnEvent(1);
		}
		dwnBtn.onMouseDown = function(){
			if(this._visible == true){
				if(this.hitTest(_root._xmouse, _root._ymouse, false)){
					this.btnEvent(2);
					scrollParent.dwnscroll = 1;
				}
			}
		}
		dwnBtn.onMouseUp = function(){
			if(this.hitTest(_root._xmouse, _root._ymouse, false)){
				this.btnEvent(1);
			}
			else{
				this.btnEvent(0);
			}
			scrollParent.dwnscroll = 0;
		}
		dwnBtn.onRollOut = function(){
			this.btnEvent(0);
		}
		dwnBtn.onRollOver = function(){
			this.btnEvent(1);
		}
 
		inc = setInterval(Delegate.create(this, frameLoop),10);
	}
 
	private function frameLoop(){
		if(scrollObj.upscroll == 1){
			if(tClip.scroll > 1){
				scrollObj.yPos -= 1;
			}
			scrollBar._y = (((tClip.scroll-1)/(tClip.maxscroll-1)) * (scrollObj.barslack)) + scrollObj.topy;
		}
		if(scrollObj.dwnscroll == 1){
			if(tClip.scroll < tClip.maxscroll){
				scrollObj.yPos += 1;
			}
			scrollBar._y = (((tClip.scroll-1)/(tClip.maxscroll-1)) * (scrollObj.barslack)) + scrollObj.topy;
		}
 
		if(scrollStatus){
			var dirStat:Number = 0;
			scrollObj.dwnscroll == 1 ? dirStat = -1:null;
			scrollObj.upscroll == 1 ? dirStat = 1:null;
			if(tClip.scroll != scrollObj.yPos){
				easeMainClip(tClip,scrollObj.yPos,easeIn,dirStat);
			}
			if(autoOn){
				if(tClip.maxscroll < 2){
					setScrollStatus(false);
				}
				var checkScrollDist:Number = tClip.maxscroll;
				if(scrollObj.scrolldist != checkScrollDist){
					//reset size - ;
					setSizes();
				}
			}
 
		}
		else{
			if(autoOn){
				if(tClip.maxscroll > 1){
					setScrollStatus(true);
				}
			}
		}
		updateAfterEvent();
	}
	private function easeMainClip(obj,val,ease,dir){
		if(ease > 0){
			if(dir == 0){
				if(Math.ceil(obj.scroll) > val){
					dir = -1;
				}
				else if(Math.ceil(obj.scroll) < val){
					dir = 1;
				}
			}
			if(dir == -1){
				obj.scroll -= Math.ceil((obj.scroll - val)/ease);
			}
			else if(dir == 1){
				obj.scroll += Math.ceil((val - obj._y)/ease);
			}
			else{
				obj.scroll = val;
			}
		}
		else{
			obj.scroll = val;
		}
	}
 
}

Demo:
OK, so my wife has been taking out all the halloween clothes and decorations this weekend. Maybe a little of that is rubbing off on me.

Source Here

Update:

The class has been updated to version (2.0), please re-download to keep current. This class and updates are based on the HDScrollMC class. http://www.taterboy.com/blog/2008/09/easy-flash-custom-scrollbar-class-as2/

Technorati Tags: , ,

Related Posts:

|

1 Comment »

  1. [...] Easy Custom Scrollbar Class for TextFields (AS2) | Taterboy.com: Graphics, Multimedia and Such Here is the twin brother of the Easy Scrollbar MovieClip Class that works with TextFields. It does not require the masking and is perfect for Input TextFields. It has all the features of the MovieClip version except for easing. TextFields scroll one line at a time which is not very smooth. [...]

    Pingback by Good AS2 class for textfields « Ramblings — September 26, 2008 @ 9:29 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment