I’m currently implementing the revised Kirupa scroller into a project of mine, and have settled on working with MichaelxxOA’s great class. Here’s my code:
import mx.utils.Delegate;
class Scroller
{
// Scroll movieclips
private var backToTop_mc:MovieClip; // back to top button
private var content_mc:MovieClip; // content
private var btnUp_mc:MovieClip; // btn UP
private var btnDown_mc:MovieClip; // btn DOWN
private var scroller_mc:MovieClip; // scroll or dragger
private var scrollBackground_mc:MovieClip // scroll's background
private var mask_mc:MovieClip; // content's mask
// Positions / Heights
private var left:Number; // scroller limits (x, y)
private var top:Number;
private var right:Number;
private var bottom:Number;
// Settings
private var mouseListener:Object;
private var actual_speed, move_speed:Number = 10; // how fast the dragger will move
private var scrollable:Number = 0; // how much of our content can be scrolled, defaults at 0
private var top_scroll:Number = 0;// where our content will sit when it is at 0% scrolled, defaults at 0.
private var newY:Number;
private var isEasing:Boolean = false;
// Constructor
public function Scroller(content:MovieClip, mask:MovieClip, btnUp:MovieClip, btnDown:MovieClip, scroll:MovieClip, scrollbg:MovieClip, backToTop:MovieClip)
{
this.content_mc = content;
this.mask_mc = mask;
this.backToTop_mc = backToTop;
this.btnUp_mc = btnUp;
this.btnDown_mc = btnDown;
this.scroller_mc = scroll;
this.scrollBackground_mc = scrollbg;
this.left = this.scrollBackground_mc._x;
this.top = this.scrollBackground_mc._y;
this.right = this.scrollBackground_mc._x;
this.bottom = this.scrollBackground_mc._y + (this.scrollBackground_mc._height - scroller_mc._height);
//trace("this.left >> " + this.left)
//trace("this.top >> " + this.top)
//trace("this.right >> " + this.right)
//trace("this.bottom >> " + this.bottom)
this.mouseListener = new Object();
Mouse.addListener(this.mouseListener);
this.mouseListener.onMouseWheel = Delegate.create(this, mouseWheel);
this.scrollable = this.content_mc._height - this.mask_mc._height;
this.top_scroll = this.content_mc._y;
//trace("this.top_scroll >> " + this.top_scroll)
initElements();
checkScrollability();
}
private function checkScrollability():Void
{
if (this.scrollable < 0)
{
this.scroller_mc._visible = false;
this.btnUp_mc._alpha = 50;
this.btnDown_mc._alpha = 50;
this.scrollBackground_mc._alpha = 50;
}
}
// ------------------------------------
// Set Easing to TRUE or FALSE
public function setEasing(value:Boolean):Void
{
this.isEasing = value;
}
// ------------------------------------
// Mouse Wheel - ACTION
private function mouseWheel(delta:Number):Void
{
var speed:Number = (delta > 0) ? this.move_speed : -this.move_speed;
this.scroller_mc._y = Math.min(this.bottom, Math.max(this.top, this.scroller_mc._y - speed));
updateContentPos();
trace(speed);
}
private function initElements():Void
{
this.content_mc.onEnterFrame = Delegate.create(this, content_onEnterFrame);
this.scroller_mc.onPress = Delegate.create(this, scroller_onPress);
this.scroller_mc.onMouseUp = Delegate.create(this, scroller_onMouseUp);
this.btnUp_mc.onPress = Delegate.create(this, btnUp_onPress);
this.btnUp_mc.onDragOut =
this.btnUp_mc.onRelease = Delegate.create(this, btnUp_delete_onEnterFrame);
this.btnDown_mc.onPress = Delegate.create(this, btnDown_onPress);
this.btnDown_mc.onDragOut =
this.btnDown_mc.onRelease = Delegate.create(this, btnDown_delete_onEnterFrame);
this.backToTop_mc.onPress = Delegate.create(this, backToTop_onPress);
this.backToTop_mc.onDragOut =
this.backToTop_mc.onRelease = Delegate.create(this, backToTop_delete_onEnterFrame);
}
// ------------------------------------
// Inicializating Elements actions:
// ------------------------------------
// Content MC - ACTION
private function content_onEnterFrame():Void
{
if (this.isEasing)
{
var jump = this.newY - this.content_mc._y;
/*
* Original SOLUTION (have bugs)
*/
//this.content_mc._y += (this.newY - this.content_mc._y) >> this.move_speed;
/*
* SOLUTION 1
*/
if(jump > 0)
{
this.content_mc._y += Math.ceil(jump / 10)
} else
{
this.content_mc._y += Math.floor(jump / 10)
}
/*
* SOLUTION 2
*/
/*if(Math.abs(jump) > (Math.pow(2, this.move_speed)))
{
this.actual_speed = this.move_speed;
}
if(Math.abs(jump) > (Math.pow(2, this.actual_speed)))
{
this.content_mc._y += jump >> this.actual_speed;
} else
{
if(this.actual_speed > 0)
{
this.actual_speed--;
} else
{
this.content_mc._y = this.newY;
}
}*/
//trace("new: " + this.newY + " // actual: " + this.content_mc._y + " // jump: " + jump)
return;
}
this.content_mc._y = this.newY;
}
// ------------------------------------
// Scroller MC - ACTIONS
private function scroller_onPress():Void
{
startDrag(this.scroller_mc, false, this.left, this.top, this.right, this.bottom);
this.scroller_mc.onMouseMove = Delegate.create(this, scroller_onMouseMove);
}
private function scroller_onMouseMove():Void
{
updateContentPos();
}
private function scroller_onMouseUp():Void
{
this.scroller_mc.stopDrag();
delete this.scroller_mc.onMouseMove;
}
private function updateContentPos():Void
{
var percent_scrolled:Number = (this.scroller_mc._y - this.scrollBackground_mc._y) / (this.scrollBackground_mc._height - this.scroller_mc._height);
// instead of setting the _y property directly, we simple set newY
// that way we can adjust how we handle the new Y coordinate we'd like to move to
this.newY = Math.round(this.top_scroll - (percent_scrolled * this.scrollable));
}
// ------------------------------------
// Button UP MC - ACTIONS
private function btnUp_onPress():Void
{
this.btnUp_mc.onEnterFrame = Delegate.create(this, btnUp_onEnterFrame);
}
private function btnUp_delete_onEnterFrame():Void
{
delete this.btnUp_mc.onEnterFrame;
}
private function btnUp_onEnterFrame():Void
{
this.scroller_mc._y = Math.max(this.top, this.scroller_mc._y - this.move_speed);
updateContentPos();
trace(move_speed);
}
// ------------------------------------
// Button DOWN MC - ACTIONS
private function btnDown_onPress():Void
{
this.btnDown_mc.onEnterFrame = Delegate.create(this, btnDown_onEnterFrame);
}
private function btnDown_delete_onEnterFrame():Void
{
delete this.btnDown_mc.onEnterFrame;
}
private function btnDown_onEnterFrame():Void
{
this.scroller_mc._y = Math.min(this.bottom, this.scroller_mc._y + this.move_speed);
updateContentPos();
trace(move_speed);
}
// ------------------------------------
// Button BackToTop - ACTIONS
private function backToTop_onPress():Void
{
this.backToTop_mc.onEnterFrame = Delegate.create(this, backToTop_onEnterFrame);
}
private function backToTop_delete_onEnterFrame():Void
{
delete this.backToTop_mc.onEnterFrame;
}
private function backToTop_onEnterFrame():Void
{
this.scroller_mc._y = this.top;
updateContentPos();
}
}
In my application (for a CD-ROM), I’m loading in separate SWF files into a holder mc in a main movie. Most of the individual movies I’m loading use the scroller class. The problem I’m experiencing is that I think that each time I load a new movie in, this code in the class is just adding a new listener to Mouse, rather than replacing the one there:
this.mouseListener = new Object();
Mouse.addListener(this.mouseListener);
this.mouseListener.onMouseWheel = Delegate.create(this, mouseWheel);
So for example if I click three different links in my app, the mouse listener fires of the function mouseWheel 3 times for one mouse wheel flick, scrolling the content 3 times instead of once. As you can imagine, the more links I click, the more haywire it gets, eventually just jumping right to the bottom of the content with one flick of the mousewheel. I know that mouseWheel is firing multiple times with one mousewheel flick (+1 more time each time I clicked a link and then scroll), as I’ve traced the speed variable and can see how many times the function is being called.
Does anyone have any ideas how to get round this? I’ve tried Mouse.removeListener(mouseListener) just before Mouse.addListener(this.mouseListener) but no luck, it just reports a value of false all the time.
Any help appreciated…