Investigate into Portfolio Multi Media Tab Gallery - 1

来源:互联网 发布:淘宝助理与千牛的区别 编辑:程序博客网 时间:2024/06/07 20:12

这个gallery的作者是oxylus,oxylus其实是一个工作室或者公司,在美国的各大web程序网络商场经常见到他们的作品。


p-m-media tab gallery


这个程序有自带的CMS,是基于PHP实现的,不过看起来有些问题,我没有搭建成功,所以可能不会考虑花时间研究。


Now, let's start. According to the .fla file, the only instance on the stage in editor is a so-called 'tabs-list' type Movieclip, its class definition is: com.oxylusflash.mmGallery.TabsList, so that is the entry of the whole program, and where we should start at.


TabsList


There is no big difference between this program entry and others, it has a method: init(), and set up an xml loader within it, then do the init stuff in the complete handler. Something different is:


The TabsList class is main entry, but it only represent one visual module: top menu. It creates the other two main visual component: ThumbsGrid and FileViewer, but add them to the root-namely the stage, as its own siblings. So although the main layout of stage is:


stage-structure


The top logic is put on TabsList class, and it has the handlers of handling all global events:


top-logics


Which means, a sub module contains the whole program's top, global logic. Generally, we won't do that. We always put the logic based on the displayObject's hierarchy.


There are some tricks in TabsList definition:

1. The author wanted to chain the positioning of all three visual modules up together, and forbidden the change of dimension, he overrode the methods:

override public function get width():Number { return bgMc.width; }override public function get height():Number { return bgMc.height; }override public function set width(value:Number):void { }override public function set height(value:Number):void { }override public function get x():Number { return super.x; }override public function set x(value:Number):void {if (thumbsGrid){thumbsGrid.x = value;}if (fileViewer){fileViewer.x = value;}super.x = value;}override public function get y():Number { return super.y; }override public function set y(value:Number):void {if (thumbsGrid){thumbsGrid.y = value + settings.tabsBgHeight;}if (fileViewer){fileViewer.y = value;}super.y = value;}

2. To make sure the init will do run, within constructor:


if (stage){init();}else{this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);}

and within the added-to-stage listener:


this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);init();

Highlights:


stage.loaderInfo.parameters.xmlFile

http://mc-computing.com/languages/ActionScript/Getting_html_data.html


So, the tabsList's main components is a handful of Tabs, predictably, it sets up its children, and animation, and hook them up, the only important thing is it will dispatch SELECT event when it got clicked. But there are two doubtful points, how could CRT_SEL keep track of the right selected tab, and doesn't normalState need to set its mouseEnabled to false(according to hitArea)?

Some discuss about hitArea:

http://ticore.blogspot.com/2010/08/flash-as3-hitarea-advanced-trick.html


One interesting point: the author separate the event type declaration and event its own definition, he tied the event type string('SELECT') with the dispatcher(Tab) rather than event(PEvent).


ThumbsGrid


Its main responsibility is as a container of thumbnails, and it would create them, show them with pagination, animate them, and response to clicking on them. And the animation effect of revealing thumbnails is realized within its method: generateThumbs() and arrangeThumbs().


I was wondering how did the author design the logic for loading the thumb image and showing them with animation. First of all, it has an interface for its parent: setData(), its for sending the XML node to it of that album. Within setData(), it does some resetting, and it calls generateThumbs(), andarrangeThumbs() consequently.


And what generateThumbs() does:


private function generateThumbs():void{/** * Remove previous if any. */if (thumbLdr){try{thumbLdr.close();thumbLdr.unload();}catch(error:Error) { }thumbLdr.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, thumbLdr_ioErrorHandler);thumbLdr.contentLoaderInfo.removeEventListener(Event.INIT, thumbLdr_initHandler);thumbLdr = null;}thumbLdr = new Loader();thumbLdr.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, thumbLdr_ioErrorHandler, false, 0, true);thumbLdr.contentLoaderInfo.addEventListener(Event.INIT, thumbLdr_initHandler, false, 0, true);if (tnsHldr){tnsArr = null;this.removeChild(tnsHldr);tnsHldr = null;startIdx = 0;}/** * Add new. */if (xmlData){tnsHldr = this.addChildAt(new Sprite, Math.min(this.getChildIndex(leftArw), this.getChildIndex(rightArw))) as Sprite;tnsArr = new Array();for each(var item:XML in xmlData.item){var tn:Thumbnail = tnsHldr.addChild(new Thumbnail(item)) as Thumbnail;tn.addEventListener(Thumbnail.TOOLTIP_SHOW, tn_tooltipShowHandler, false, 0, true);tn.addEventListener(Thumbnail.TOOLTIP_HIDE, tn_tooltipHideHandler, false, 0, true);tn.addEventListener(Thumbnail.VIEW, tn_viewHandler, false, 0, true);tnsArr.push(tn);}loadIdx = -1;loadNext();}}

The first part is cleaning up the variables, including the array of thumbnails and loader, removing them from display-list. The second part is building them up again, and call loadNext() to initiate the loading loop procedure. This procedure will load each thumbnail's picture. In its handler:


private function thumbLdr_initHandler(e:Event):void {if (tnsArr && tnsArr[loadIdx]){tnsArr[loadIdx].addThumbImg(thumbLdr.content);loadNext();}}

And after calling generateThumbs(),setData() callsarrangeThumbs() immediately.That means the procedure of loading is going as well as the revealing of thumbnails, these two process are parallel,arrangeThumbs() reveals thumb one by one, from 30 pixel below to its position and its just because the image size is small, the loading time is very short, so before animating the thumbnail, its image has been loaded already. There is no logic to guarantee that, there is no secret. 

Besides, arrangeThumbs() is also be called when the stage is resized, and when nav buttons get clicked, so its logic is special, since sometime it only should re-position the thumbnails, and no need to refresh them. 


arrangeThumbs-flowchart

Highlights:


When destroying a Loader object, the approach here:


if (thumbLdr){try{thumbLdr.close();thumbLdr.unload();}catch(error:Error) { }thumbLdr.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, thumbLdr_ioErrorHandler);thumbLdr.contentLoaderInfo.removeEventListener(Event.INIT, thumbLdr_initHandler);thumbLdr = null;}

It calls close() and unload() methods of Loader, and one interesting thing: the author didn't use COMPLETE event to capture load finished, he used INIT event instead. 

Loader

http://www.actionscript.org/forums/showthread.php3?t=160781



ThumbNail


Its public method addThumbImg() is not just adding image to display-list, it also sets up a tween animation to show the picture gradually. 


Two points to note: in ThumbsGrid'sthumbLdr_inithandler(), it passes loader.content to addThumbImg(), and that should be a Bitmap object:


tnsArr[loadIdx].addThumbImg(thumbLdr.content);

in addThumbImg(), it create a brand-new Bitmap, and its content is a copy of loader's content, the author made a cloned copy by using BitmapData.draw():


var bmp:BitmapData = new BitmapData(TabsList.settings.thumbWidth, TabsList.settings.thumbHeight, false, 0);bmp.draw(content);imgMc = this.addChild(new Bitmap(bmp)) as Bitmap;

Then imgMc is a valid displayObject, and you can do anything with it.


The other one is: in the handler of remove-from-stage, ThumbNail would call BitmapData.dispose() to release the memory space allocated for the images:


if (imgMc){if (Tweener.isTweening(imgMc)) Tweener.removeTweens(imgMc);imgMc.bitmapData.dispose();}


ArrowButton


This class is a good sample for demonstration of how to using base class member in inheritance, and the meaning of mouseEnabled, actually this attribute is not as easy as it seems to be, we may go back to this attribute laterly:


override public function set mouseEnabled(value:Boolean):void {super.mouseEnabled = value;this.buttonMode = value;Tweener.addTween(this, { alpha: value ? 1 : TabsList.settings.navArrowDisabledAlpha, time: 0.3, transition: "easeoutquad" });}

This is another sample of taking advantage of setter function, to bundle the necessary operation together. This is not necessary from pure technical perspective, but it makes code concise and beautiful.


Hightlights:


There are two kind of event flow design so far:

1. it's more like a linked chain, such as ThumbNail dispatches VIEW pEvent to ThumbsGrid when gets clicked, and ThumbsGrid dispatches THUMB_VIEW pEvent to TabsList when it gets  VIEW, then TabsList handle that, it shows FileViewer.

fir-event-flow


2. for one specific event on specific object, there are multiple handlers to handle it during its bubbling stage. Like ArrowButton.


second-event-flow


原创粉丝点击