Wednesday, November 5, 2008

AS3: Scrollbar class

Origion source from http://www.flashscaper, I optimize to make it better.

All you need is :

+ a movie clip contains : scrollermc, trackmc, (upmc and downmc are optional), this movie has a linkage with utils.Scrollbar class.

+ how to use: call init function like : scrollbar.init(movieNeedScrollbar);

Scrollbar function :
  • dragable, up, down
  • click on track
  • mouse wheel
------------------------------------------

package utils { //utils.Scrollbar
import caurina.transitions.Tweener;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;

/**
* ...
* @author binhdocco
*/
public class Scrollbar extends MovieClip {

private var content: MovieClip;
private var transition: String;
private var transitionTime: Number;
private var hasArrow: Boolean;
private var dragRect: Rectangle;

public var scrollermc: MovieClip;
public var trackmc: MovieClip;
public var upmc: MovieClip;
public var downmc: MovieClip;
public var contentY: Number;
private var range: Number;
private var top: Number;
private var bottom: Number;
private var isUp: Boolean = false;
private var isDown: Boolean = false;
private var speedScroll: Number = 3;
private var ratio:Number;

public function Scrollbar() {

}

public function init(content: MovieClip, transition: String = "linear", transitionTime: Number = 0.15, hasArrow: Boolean = true, hasWheel: Boolean = true):void {
this.content = content;
this.transition = transition;
this.transitionTime = transitionTime;
this.hasArrow = hasArrow;

if (this.content.height <= this.height) {
this.visible = false;
}
contentY = this.content.y;
if (!this.hasArrow) {
if (upmc) {
this.trackmc.y = 0;
this.scrollermc.y = 0;
this.trackmc.height += this.upmc.height;
this.removeChild(upmc);
}
if (downmc) {
this.trackmc.height += this.downmc.height;
this.removeChild(downmc);
}
}

//dragRect
top = this.trackmc.y;
bottom = top + this.trackmc.height - this.scrollermc.height;
dragRect = new Rectangle(this.trackmc.x, top, 0, bottom - top);
range = this.height - 5;
ratio = (content.height - range)/(this.trackmc.height - scrollermc.height);
//create mask
var mask: Sprite = new Sprite();
mask.graphics.beginFill(0xFF0000);
mask.graphics.drawRect(content.x, content.y, content.width + 5, this.height);
mask.graphics.endFill();
this.parent.addChild(mask);
this.content.mask = mask;

this.scrollermc.addEventListener(MouseEvent.MOUSE_DOWN, onScrollerMouseDown);
this.stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
this.trackmc.addEventListener(MouseEvent.CLICK, onTrackClick);

if (hasWheel) {
this.content.addEventListener(MouseEvent.MOUSE_WHEEL, onContenMouseWheel);
this.addEventListener(MouseEvent.MOUSE_WHEEL, onContenMouseWheel);
}

if (this.hasArrow) {
this.upmc.addEventListener(MouseEvent.MOUSE_DOWN, onArrowMouseDown);
this.downmc.addEventListener(MouseEvent.MOUSE_DOWN, onArrowMouseDown);
}
}

public function update():void {
this.content.y = contentY;
if (this.content.height <= this.height) {
this.visible = false;
} else {
this.visible = true;
}
ratio = (content.height - range)/(this.trackmc.height - scrollermc.height);
}

public function gotoTop():void {
Tweener.addTween(this.scrollermc, { y: top, time: 0.5, onStart: addEnterFrame, onComplete: stopScroll} );
}

public function gotoEnd():void {
Tweener.addTween(this.scrollermc, { y: bottom, time: 0.5, onStart: addEnterFrame, onComplete: stopScroll} );
}
//EVENTS HANDLER

private function onTrackClick(e:MouseEvent):void {
var mouseY: Number = this.mouseY;
var scrollY: Number = this.scrollermc.y;
var destY: Number = mouseY - this.scrollermc.height / 2;
if (destY >= bottom) {
destY = bottom;
}
if (destY <= top) {
destY = top;
}
Tweener.addTween(this.scrollermc, { y: destY, time: 0.5, onStart: addEnterFrame, onComplete: stopScroll} );

}

private function onContenMouseWheel(event:MouseEvent):void {
if (event.delta < 0) {
if (this.scrollermc.y < bottom) {
this.scrollermc.y += Math.abs(event.delta)*2;
if (this.scrollermc.y >= bottom) {
this.scrollermc.y = bottom;
}
startScroll();
}
} else {
if (this.scrollermc.y > top) {
this.scrollermc.y -= event.delta*2;
if (this.scrollermc.y <= top) {
this.scrollermc.y = top;
}
startScroll();
}
}
}


private function onArrowMouseDown(e:MouseEvent):void {
if (e.target.name == this.upmc.name) {
isUp = true;
this.upmc.addEventListener(Event.ENTER_FRAME, onUpEnterFrame);
} else if (e.target.name == this.downmc.name) {
isDown = true;
this.downmc.addEventListener(Event.ENTER_FRAME, onDownEnterFrame);
}
}

private function onUpEnterFrame(e:Event):void {
if (isUp) {
if (this.scrollermc.y > top) {
this.scrollermc.y -= speedScroll;
if (this.scrollermc.y <= top) {
this.scrollermc.y = top;
}
startScroll();
}
}
}

private function onDownEnterFrame(e:Event):void {
if (isDown) {
if (this.scrollermc.y < bottom) {
this.scrollermc.y += speedScroll;
if (this.scrollermc.y >= bottom) {
this.scrollermc.y = bottom;
}
startScroll();
}
}
}

private function onStageMouseUp(e:MouseEvent):void {
if (isUp) {
this.upmc.removeEventListener(Event.ENTER_FRAME, onUpEnterFrame);
isUp = false;
}
if (isDown) {
this.downmc.removeEventListener(Event.ENTER_FRAME, onDownEnterFrame);
isDown = false;
}
this.scrollermc.stopDrag();
stopScroll();
}

private function onScrollerMouseDown(e:MouseEvent):void {
stopScroll();
this.scrollermc.startDrag(false, dragRect);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private function addEnterFrame():void {
stopScroll();
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private function onEnterFrame(e:Event = null):void {
startScroll();
}

// FUNCTIONS
private function stopScroll():void {
this.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private function startScroll():void {
var sPos: Number = ratio*(this.trackmc.y - scrollermc.y ) + contentY;
Tweener.removeTweens(this.content);
Tweener.addTween(this.content, { y: sPos, time:transitionTime, transition:transition } );
}
}

}
}

Thursday, October 30, 2008

PureMVC : Basic step

All projects using PureMVC must have only one ApplicationFacade class to control all process. Along with ApplicationFacade is StartupCommand, which registers some Proxies and Mediators.

Example with a ImageSlideshow project :

All you need are :

MVCProject.as ---> init ApplicationFacade
ApplicationFacade ---> excute StartupCommand ---> register SiteDataProxy, StageMediator with viewComponent is Stage.
SiteDataProxy ---> load external xml file, sendNotification to StageMediator
StageMediator ---> register ContainerMediator with viewComponent is Container sprite.


Very interesting.

Wednesday, October 22, 2008

10 tips for working with PureMVC

  1. Think in (Pure)MVC

    How do I start using PureMVC? Short answer: Just think in (Pure)MVC! As its named says, PureMVC based on the classic Model-View-Controller design meta-pattern. Using the Facade-pattern you don’t instantiate the core actors directly, but every member of PureMVC has its own and clear defined role:
    - Proxies = Model

    - Mediator and its ViewComponents = View
    - Commands = Controller

  2. Create an API for View Components

    A View Component might be a standard UI component (e.g. DataGrid) or a custom component (e.g. a world within a game) or whatever. Don’t use its public methods directly. In order to change its state or behavior create an API.

    One of the advantage of PureMVC is to be neutral to the technologies being used. An example: I’ve built a “pure” Flash application based on PureMVC without using the Flex Framework. The same app will be ported to an AIR application for using AIR’s great File system API. The View Components have to be changed using the Flex Framework, but not the Mediators or any other actors of PureMVC.

  3. Use one Mediator for multiple View Components

    To coordinate more than one View Component closely, use one Mediator only. In other words: Not all Views need a Mediator. For example: Assume a ApplicationControlBar containing a TextInput , and a Button or something else. Then create just one Mediator for the ApplicationControlBar called ApplicationControlBarMediator and refer to the missing components casted as a second, third, etc. View Component.

  4. Let’s Events bubble up

    What happens if you don’t want to use multiple View Components within a Mediator? In order to handle user interactions with multiple View Components let’s bubble Events from the nested children of a View Component up.

    For example: Clicking any Button within a View Component will fired up a custom Event which the Mediator is listen to. So the Mediator don’t have to know about the existing Button or about any other child of its View Component, just about the custom Event bubbled up.

  5. Communicate using Notifications as often as possible

    Notifications are the “Events” of PureMVC. For communicating between the three tiers Model, View and Controller use Notifications for the following scenarios as often as possible:

    (communication from -> to)
    - Mediator -> Proxy (via mapped Commands)
    - Proxy -> Mediator
    - Proxy -> Command
    - Commands -> Mediator

    Even if it’s possible to retrieve a Proxy from a Mediator, don’t change the Proxy from a Mediator directly rather than sending a Notification using a mapped Command. It’s a bad practice to change a Proxy (Model) from a Mediator (View) directly without using a Command (Controller).

  6. Use Commands / MacroCommands as often as possible

    Commands are doing the job at the Controller side: Retrieving and interacting Proxies, communicating with Mediators or executing other Commands. Even if a Command used only once or it has only two lines of code, use it as often as possible. To execute a Command once again anywhere or anytime within your application, you have to send just a Notification. In the future it’s easy to enlarge the Command with more complex actions. And - that’s very important - you always know, who the actor for changing the Proxy (Model) is.

    Question: Have you had to execute more than one Command in a particular order? Use MacroCommands to execute multiple SubCommands (which means “simple” Commands) sequentially.

  7. Use Remote Proxy to send and receive server-side data

    To send and receive data between the application tier use Proxies called Remote Proxies. That’s not a special kind of a PureMVC Proxy, just a location based on a Proxy to organize the server calls such as HTTPServices, RemoteObjects or whatever.

    For example: To call a server-side RemoteObject to login a user create Proxy called LoginProxy. The LoginProxy does all the job to communicate with the server-side, which means sending and receiving data. Whenever you’ll change the server-side implementation for the LoginProcess, you’ll have to change one location within your application only - the LoginProxy.

  8. Remove unused Mediators

    In some cases you don’t use a Mediator and its View Components anymore. Then remove the Mediator using facade.removeMediator(MyMediator.NAME); in conjunction with a self created destroy() method to remove the ViewComponent including all listeners, timer, references, etc. for a successful garbage collection.

  9. The Power of VO’s (Value Objects)

    The place to store data within the Model are the Proxies - that’s right. The View Components have no need to know the Facade and the rest of the PureMVC application - that’s right, too. This means that the View Component has no access to the Model data directly.

    To avoid this issue store within the View Component a reference to the data using Value Objects (VO’s). The VO’s are not a core actor of PureMVC and in conjunction with the Data Binding feature of Flex are a powerful way to react changes in the Model data without breaking rules.

  10. Courseware available

  11. Cliff Hall has done an awesome job: You’ll find not only excellent documentations about the “Framework Overview“, “Best Practices” and a “Conceptual Diagram“, also a very, very, very helpful Courseware. Check it out!

Enjoy PureMVC and Happy Holidays ;-) !


Source from http://www.websector.de/blog/2007/12/25/10-tips-for-working-with-puremvc/

Thursday, September 25, 2008

Flexlib Components

The FlexLib project is a community effort to create open source user interface components for Adobe Flex 2 and 3.

Current components: AdvancedForm, Base64Image, EnhancedButtonSkin, CanvasButton, ConvertibleTreeList, Draggable Slider, Fire, Highlighter, HorizontalAxisDataSelector IconLoader, ImageMap, PromptingTextArea, PromptingTextInput, Scrollable Menu Controls, SuperTabNavigator, Alternative Scrolling Canvases, Horizontal Accordion, TreeGrid, FlowBox, Docking ToolBar, Flex Scheduling Framework

website : http://code.google.com/p/flexlib/

Friday, September 19, 2008

Problem solve: SuperTabNavigator - flexlib - style close tab button

Problem: use 'closeButtonStyleName' for close button style in flexlib.SuperTabNavigator tab, it shows a circle without style.

Solve: use 'tabCloseButtonStyleName' instead.

Note: too tired of this problem.

AS3 Tips

  • Get variables form flashvars :
---------------------------
var paramObj:Object = LoaderInfo(this.root.loaderInfo).parameters;
for (var keyStr in paramObj) {
var valueStr = String(paramObj[keyStr]);
trace(keyStr + " : " + valueStr );
}

---------------------------
  • Shuffe an array:
---------------------------
function randomAnArray(tArray:Array):void {
function randomSort(a:Object, b:Object):int {
return Math.round(Math.random()*-1+Math.random());
}
tArray.sort(randomSort);
}

var testArray: Array = [1,2,3,4,5];
randomAnArray(testArray);

trace(testArray);
---------------------------

Query service and get respone

var variables:URLVariables = new URLVariables();
variables.param1 = param1;
variables.param1 = param1;

var request:URLRequest = new URLRequest();
request.url = "testpage.php";
request.method = URLRequestMethod.POST; //can be GET
request.data = variables;

var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;  // can be XML
loader.addEventListener(Event.COMPLETE, completeHandler);
loader.load(request);


function completeHandler(event:Event):void {
    trace(event.target.data)// show data respone
}

10 common mistakes when building AIR applications

Adobe AIR has grown immensely popular over the past months. With its popularity, many new applications have been released. During this period, the following 10 issues have been the mistakes I have seen most often among developers. Hopefully, this list can help you avoid the same mistakes when building your next AIR application.

Link