AS3 Content Scroller

Something to play with until some components are released:

[AS]package com.onebyonedesign.as3.utils.ui {

import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.Rectangle;

/**

  • @author Devon O. Wolfgang
  • @date 29NOV06
    */

public class ContentScroller {

private var _mask:Sprite;
private var _content:Sprite;
private var _dragger:Sprite;
private var _easeRate:Number;
private var _direction:String;
private var _bounds:Rectangle;
private var _setSize:Boolean;

private var _scrollValue:Number;
private var _orgY:Number;
private var _orgX:Number;

/**
*

  • @param content Sprite which will be scrolled by ContentScroller
  • @param mask Sprite which will mask the scrolling content (mask should be set in another class)
  • @param scrollbar Sprite which will be used to do the scrolling
  • @param ease Number which controls amount of ease in scrolling. Higher the number, the more ease. 0 or 1 will have no ease.
  • @param direction String specifying the direction of the scroll. Can either be “vertical” or “horizontal”.
  • @param setDraggerSize Boolean which decides whether to stretch the width or height of the scrollbar in proportion to the amount of content.

*/
public function ContentScroller(content:Sprite, mask:Sprite, scrollbar:Sprite, ease:Number = 0, direction:String = “vertical”, setDraggerSize:Boolean = false) {
_setSize = setDraggerSize;
_content = content;
_mask = mask;
_dragger = scrollbar;
_easeRate = ease;
if (_easeRate < 1) _easeRate = 1;
_direction = direction;

switch(_direction) {
case “horizontal” :
initHorizontal();
break;
case “vertical” :
initVertical();
break;
default :
trace (“CONTENT SCROLLER ERROR: direction argument should be either “vertical” or “horizontal”.”);
break;
}
}

private function initHorizontal():void {
if (_mask.width < (_content.width - 1)) {
if (_setSize) _dragger.width = Math.ceil((_mask.width / _content.width) * _mask.width);
_scrollValue = _mask.width - _dragger.width;
_orgX = _dragger.x;
_bounds = new Rectangle(_orgX, _dragger.y, _scrollValue, 0);

addListeners();

}
}

private function initVertical():void {
if (_mask.height < (_content.height - 1)) {
if (_setSize) _dragger.height = Math.ceil((_mask.height / _content.height) * _mask.height);
_scrollValue = _mask.height - _dragger.height;
_orgY = _dragger.y;
_bounds = new Rectangle(_dragger.x, _orgY, 0, _scrollValue);

addListeners();

}
}

private function addListeners():void {
_dragger.addEventListener(MouseEvent.MOUSE_DOWN, onDraggerPress, false, 0, true);
_dragger.addEventListener(MouseEvent.MOUSE_UP, onDraggerUp, true, 0, true);
_dragger.stage.addEventListener(MouseEvent.MOUSE_UP, onDraggerUp, false, 0, true);
}

private function onDraggerPress(me:MouseEvent):void {
_ratio = (_dragger.y - _orgY) / _scrollValue;
_ty = _orgY - (_content.height - _mask.height) * _ratio;
_dragger.startDrag(false, _bounds);
if (_direction == “vertical”) {
_dragger.addEventListener(MouseEvent.MOUSE_MOVE, onVerticalScroll, false, 0, true);
_dragger.stage.addEventListener(MouseEvent.MOUSE_MOVE, onVerticalScroll, false, 0, true);
} else if (_direction == “horizontal”) {
_dragger.addEventListener(MouseEvent.MOUSE_MOVE, onHorizontalScroll, false, 0, true);
_dragger.stage.addEventListener(MouseEvent.MOUSE_MOVE, onHorizontalScroll, false, 0, true);
}
}

private function onDraggerUp(me:MouseEvent):void {
_dragger.stopDrag();

_dragger.removeEventListener(MouseEvent.MOUSE_MOVE, onVerticalScroll);
_dragger.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onVerticalScroll);

_dragger.removeEventListener(MouseEvent.MOUSE_MOVE, onHorizontalScroll);
_dragger.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onHorizontalScroll);
}

private function onVerticalScroll(me:MouseEvent):void {
me.updateAfterEvent();
if (!_content.willTrigger(Event.ENTER_FRAME)) _content.addEventListener(Event.ENTER_FRAME, moveVertical, false, 0, true);
}

private function onHorizontalScroll(me:MouseEvent):void {
me.updateAfterEvent();
if (!_content.willTrigger(Event.ENTER_FRAME)) _content.addEventListener(Event.ENTER_FRAME, moveHorizontal, false, 0, true);
}

private function moveVertical(e:Event):void {
var ratio:Number = (_dragger.y - _orgY) / _scrollValue;
var ty:Number = _orgY - (_content.height - _mask.height) * ratio;
var dist:Number = ty - _content.y;
var moveAmount:Number = dist / _easeRate;
_content.y += moveAmount;
if (Math.abs(_content.y - ty) < 1) {
_content.removeEventListener(Event.ENTER_FRAME, moveVertical);
_content.y = ty;
}
}

private function moveHorizontal(e:Event):void {
var ratio:Number = (_dragger.x - _orgX) / _scrollValue;
var tx:Number = _orgX - (_content.width - _mask.width) * ratio;
var dist:Number = tx - _content.x;
var moveAmount:Number = dist / _easeRate;
_content.x += moveAmount;
if (Math.abs(_content.x - tx) < 1) {
_content.removeEventListener(Event.ENTER_FRAME, moveHorizontal);
_content.x = tx;
}
}
}
}[/AS]

Usage example (use this as document class):

[AS]package {

import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;

import com.onebyonedesign.as3.utils.ui.ContentScroller;

public class ScrollTest extends Sprite {

  private var _m:Sprite; 
  private var _drag:Sprite; 
  private var _c:Sprite; 
  private var _gibberish:TextField; 
      
  private var _cs:ContentScroller; 
   
  public function ScrollTest() { 
      
     stage.frameRate = 31; 
   
     init(); 
      
  } 
   
  private function init():void { 
     // create content sprite 
     _c = new Sprite(); 
     _c.x = 100; 
     _c.y =100; 
      
     // create mask sprite 
     _m = drawRect(200, 200, 0x000000); 
     _m.x = 100; 
     _m.y = 100; 
      
     // create scrollbar sprite 
     _drag = drawRect(15, 15, 0x141414); 
     _drag.x = 300; 
     _drag.y = 100; 
      
      
     // create textfield 
     _gibberish = createText(); 
     _gibberish.x = 5; 
      
     // add the textfield to the content sprite 
     _c.addChild(_gibberish); 
      
     // mask the content with the mask 
     _c.mask = _m; 
      
     // add everything to the display list 
     addChild(_c); 
     addChild(_m); 
     addChild(_drag); 
      
     // create the scroller 
     _cs = new ContentScroller(_c, _m, _drag, 5, "vertical", true);    
  } 
   
  private function createText():TextField { 
     var tf:TextField = new TextField(); 
     var fmt:TextFormat = new TextFormat("_sans", 11, 0xCCCCCC); 
     tf.defaultTextFormat = fmt; 
     tf.background = true; 
     tf.backgroundColor = 0x141414; 
     tf.width = 190; 
     tf.height = 400; 
     tf.autoSize = TextFieldAutoSize.LEFT; 
     tf.multiline = true; 
     tf.wordWrap = true; 
     tf.selectable = false; 
     tf.mouseEnabled = false; 
     tf.text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas tempus arcu at erat. Nam accumsan ultrices augue. Morbi fermentum vestibulum tellus. Pellentesque et mauris vehicula sapien bibendum fermentum. Aliquam neque massa, elementum dapibus, ullamcorper sit amet, vulputate at, mauris. Nam imperdiet. Aliquam tempus nonummy felis. Nunc blandit dolor posuere enim. Nulla pretium purus ut orci. Praesent nibh lorem, egestas vitae, mattis quis, elementum et, erat. Etiam est sem, vestibulum sed, venenatis sit amet, placerat a, massa. Nulla ullamcorper ipsum ut massa. Morbi scelerisque tortor sit amet felis. Sed nec turpis. Fusce dui dolor, vestibulum nec, lacinia quis, venenatis non, est. Ut hendrerit, dui vel fermentum aliquam, lorem sem tempor purus, ut facilisis pede diam eu mauris. Nam ultricies. Aliquam id metus.

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus dui tellus, condimentum pellentesque, venenatis nec, tincidunt ac, risus. Nam metus magna, lobortis vitae, molestie quis, laoreet eu, purus. Integer pulvinar, mauris et consequat pellentesque, felis purus porttitor nisl, nec faucibus tortor massa quis elit. Duis auctor. In erat tortor, molestie non, hendrerit quis, consequat vel, arcu. Sed enim. Praesent magna lectus, tincidunt eget, dignissim sed, commodo id, massa. In neque risus, gravida et, molestie sit amet, pellentesque in, massa. Curabitur elementum vehicula mi. In feugiat libero non metus. Duis feugiat, diam ac adipiscing tristique, velit ligula consequat purus, vel varius ligula mauris vitae velit. Nunc vehicula. Morbi luctus leo. Duis id enim varius mi ultricies convallis. Vestibulum egestas porttitor augue. ";

     return tf; 
  } 
   
  private function drawRect(w:Number, h:Number, col:uint):Sprite { 
     var s:Sprite = new Sprite; 
     s.graphics.beginFill(col); 
     s.graphics.drawRect(0, 0, w, h); 
     s.graphics.endFill(); 
      
     return s; 
  } 

}
}[/AS]

The above script makes this: http://www.onebyonedesign.com/flash/scrolltest/

A little word of “warning” - make sure all Sprite instances are added to the display list before passing them as arguments to the class constructor…

Great code, thanks for providing it.

I have a problem. The swf file that has the ScrollTest Document Class assigned works fine, but when I load that swf from another swf file, I get this error:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at ScrollTest()

Did anyone else have this problem too? Why does this happen?

Thanks!

I’ve found the solution for that problem here: http://www.actionscript.org/resources/articles/716/2/AS3-Classes-Using-Inheritance/Page2.html

Very good tutorial with cool examples and one of them addresses exactly the problem I had. Thanks Jody Hall!

Here’s the code for someone else having the same problem:



public function ScrollTest() {
			addEventListener(Event.ADDED_TO_STAGE, addedListener);
		}
		public function addedListener(event:Event) {
			removeEventListener(Event.ADDED_TO_STAGE, addedListener);
			stage.frameRate = 31;

			init();
		}


how do I change the height of the scroller? could I change it dynamically through AS?