【原创】一个横向二级导航

本实例很简单,一级导航由于宽度是固定了的,所以不做成动态输出了,不过在xml中还是会做相关的配置(比如名称、链接等)。二级的导航就是通过读取xml中的内容类加载和显示的。先预览一下效果:点击

需要说明一点,按道理来说,点击某个导航项之后应该标示出当前所在的导航项(当前页面),这里没有实现这个需求,是因为导航是嵌入到网页文件里面的,当单击导航之后会发生跳转,为了在新打开的页面中标示出导航当前所在的导航项,我们给swf文件传值即可,所以没有必要再当前页面标示出当前所在项(跳转之后新页面通过传值的方式设定当前所在项)。不知道说明白没有,不明白先往下看应该能明白。。。

一、先配置好xml文件

保存为site-nav.xml。结构如下:

<?xml version="1.0" encoding="utf-8"?>
<site_nav>
	<top_nav name="首页" link="http://www.google.com" coo=""></top_nav>
	<top_nav name="优秀教程" link="http://www.google.com" coo="160">
		<sub_nav link="http://www.google.com">子导航一</sub_nav>
		......
		<sub_nav link="http://www.google.com">子导航七啊啊</sub_nav>
	</top_nav>
	<top_nav name="优秀教程" link="http://www.google.com" coo="160">
		<sub_nav link="http://www.google.com">子导航一</sub_nav>
		......
		<sub_nav link="http://www.google.com">子导航七啊啊</sub_nav>
	</top_nav>
</site_nav>

我没有把所有菜单项都列出来,因为有点长,比较占版面,知道xml的结构就可以了。

coo这个属性的作用是设置每个二级菜单出现的位置。首页没有二级菜单,所以没有sub_nav节点。

二、制作一级导航。

前面说了由于一级导航固定不变,所以不做动态输出了,所以我们直接在flash软件里面制作出来。一级导航只有两种状态,当鼠标移开时文字变灰,移到其上面时文字变白,我们制作好一个,其他个直接复制元件就可以了。

1、先用矩形工具根据每个菜单项的宽度和高度画一个矩形,然后转换成影片剪辑,注意,元件注册点为正中心,比如:

2、双击进本影片剪辑内部,新建一个图层,用文字工具打入菜单项文字,比如这里“首页”:

3、按F6插入一个关键帧,然后把文字的颜色改成白色的(鼠标滑过的时候改变成白色):

,时间轴上的帧应该是这样的:,第一帧记得加上“stop()”代码。

然后把背景的那个矩形的颜色的透明底改成0,这个透明底只是为了设置鼠标响应范围而画的。

4、一个菜单项制作好之后,其他的复制元件,改下文字就好了。先选择刚刚制作好的菜单项,ctrl+c、ctrl+v复制一个,然后在复制出来的菜单项上右击,在出来的右键菜单中选择“直接复制元件…”,弹出的对话框中选确定,然后双击进入这个复制出来的菜单项,双击文本进行修改。之后用同样的方法复制和制作剩余的菜单项,放到响应的位置,如下:

5、给每个菜单项命名,依次命名为nav0,nav1,…。

6、制作鼠标经过时那个跟随的红色块,你可以画出来,我是从平面里面截图的,新建一个图层,把图片拖入舞台,然后转换为影片剪辑。之后给其命名为:hover_mc

三、创建文档类MainNav.as

代码我实在Flash Develop里面写的,目前我们先不考虑二级导航的情况。代码如下:

package AS {
	//导入必要的类
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.net.navigateToURL;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	import com.greensock.TweenLite;
	import flash.display.StageScaleMode;
	//下面两个是自定义的缓动函数用的。
	import fl.motion.BezierSegment;
	import flash.geom.Point;

	public class MainNav extends MovieClip {
		//定义相关属性
		//_currentTag为当前一级菜单所在的菜单项
		private var _currentTag:int;
		//_subTag为二级菜单所在的项
		private var _subTag:int;
		//_overTag的定义主要是为了重置上个鼠标滑过时菜单项的状态的,滑过时走到第二帧,划开时又回到第一帧。
		private var _overTag:int = _currentTag;
		//xml所在路径
		private var _xmlPath:String = "site-nav.xml";
		//xml数据本身
		private var _navData:XML;
		//缓动的时间
		private var _easeDelay:Number = 2;

		public function MainNav():void {

			if (stage) {
				init();
			}else {
				addEventListener(Event.ADDED_TO_STAGE, init);
			}

		}
		private function init(e:Event=null):void {

			stage.scaleMode = StageScaleMode.NO_SCALE;
			//先加载本身,加载完成之后再加载xml文件
			loaderInfo.addEventListener(Event.COMPLETE, mainLoaded);

		}
		private function mainLoaded(e:Event):void {

			loaderInfo.removeEventListener(Event.COMPLETE, mainLoaded);
			//加载xml
			var xmlLoader:URLLoader = new URLLoader();
			xmlLoader.load(new URLRequest(_xmlPath));
			xmlLoader.addEventListener(Event.COMPLETE, xmlLoaded);
			//下面这个临时变量,主要是获取网页里面传递过来的值,网页里面传递方式形如:index-nav.swf?n=20
			//比如:n=20表示第三个一级导航项下面的第一个二级导航,n=33表示第四个一级导航下的第四个二级导航。
			//单击导航页面跳转之后导航的状态就是由这个值了决定的。
			var tempVar:int;
			tempVar = int(loaderInfo.parameters["n"]);
			//tempVar = 63;
			if (tempVar > 0) {
				//对传递过来的n进行拆分,十位数表示一级导航状态,个位数表示二级导航状态
				var str:String = String(tempVar);
				_currentTag = int(str.substr(0, 1));
				_overTag = _currentTag;
				_subTag = int(str.substr(1, 1));
			}

		}
		private function xmlLoaded(e:Event):void {

			//保存加载到的xml数据到_navData变量
			_navData = XML(e.target.data);

			//循环初始化每个一级导航项的相关设置
			for (var i = 0; i < 8; i++) {
				//动态添加一个自定义属性
				this["nav" + i].id = i;
				//按钮模式,这样就出现手型
				this["nav" + i].buttonMode = true;
				//孩子不接收鼠标事件
				this["nav" + i].mouseChildren = false;
				//添加鼠标滑过监听器,注意ROLL_OVER事件不参与冒泡
				this["nav" + i].addEventListener(MouseEvent.ROLL_OVER, mainNavOver);
				//添加单击事件侦听器
				this["nav" + i].addEventListener(MouseEvent.CLICK, mainNavClick);

			}
			//侦听鼠标移除舞台(导航)时的事件,好重置菜单状态
			this.addEventListener(MouseEvent.ROLL_OUT, outStage);

			//设置默认的状态
			this.hover_mc.x = this["nav" + _currentTag].x;
			this["nav" + _currentTag].gotoAndStop(2);

		}
		private function outStage(e:MouseEvent):void {
			//_overTag变量表示上次鼠标所在哪个菜单项上面,不等于_currentTag变量,则需要重置导航的状态
			if (_overTag != _currentTag) {
				//鼠标所在的菜单项跳转到第一帧(文字变灰)
				this["nav" + _overTag].gotoAndStop(1);
				//当前所选中的菜单项跳转到第二帧(文字变白)
				this["nav" + _currentTag].gotoAndStop(2);
				//色块缓动到当前所在菜单项下
				TweenLite.to(this.hover_mc, _easeDelay, { x:this["nav" + _currentTag].x, ease:ease } );
				//重置_overTag的值。
				_overTag = _currentTag;
			}

		}
		private function mainNavOver(e:MouseEvent):void {

			//鼠标在某个菜单项上时,这个菜单项跳转到第二帧
			e.target.gotoAndStop(2);

			if (_overTag != e.target.id) {

				//上次鼠标所在的菜单项不是本菜单项时,上个菜单项回到第一帧(文字变灰)
				this["nav" + _overTag].gotoAndStop(1);
			}
			//红色块跟随鼠标,滑到响应的菜单项下
			TweenLite.to(this.hover_mc, _easeDelay, { x:e.target.x, ease:ease } );
			//设置_overTag为当前的菜单项id
			_overTag = e.target.id;

		}
		private function mainNavClick(e:MouseEvent):void {

			if (_currentTag != e.target.id) {
				//当前菜单项和所点击的菜单项不同时,重置当前菜单项
				_currentTag = e.target.id;
				//跳转到响应的链接
				//navigateToURL(new URLRequest(_navData.top_nav[_currentTag].@link),"_top");
				trace(_navData.top_nav[_currentTag].@link);
			}

		}
		//下面这个函数是一个自定义的缓动函数,是用Easing Generator生成的,需要可以找我
		private function ease(t:Number, b:Number, c:Number, d:Number):Number{
			var points:Array = [
				{point:[0,0],pre:[0,0],post:[0,0.59]},
				{point:[0.37,1.04],pre:[0.13,1.05],post:[0.52,1.03]},
				{point:[1,1],pre:[0.68,0.92],post:[1,1]},
			];
			var bezier:BezierSegment = null;
			for (var i:int = 0; i < points.length - 1; i++) {
				if (t / d >= points[i].point[0] && t / d <= points[i+1].point[0]) {
					bezier = new BezierSegment(
						new Point(points[i].point[0], points[i].point[1]),
						new Point(points[i].post[0], points[i].post[1]),
						new Point(points[i+1].pre[0], points[i+1].pre[1]),
						new Point(points[i+1].point[0], points[i+1].point[1]));
					break;
				}
			}
			return c * bezier.getYForX(t / d) + b;
		}
	}
}

在flash环境中绑定一下这个文档类,然后就可以测试了,大致看出效果,只是还没加入二级菜单的制作。

四、加入二级菜单。

每个二级菜单项都是根据xml文件里面的设置动态生成的,他们的状态、鼠标滑过划开效果等都一样,所以我们考虑用单独的一个类来写,动态生成的时候生成这个类的实例就可以了。首先来看一下这个类吧:

package AS {
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import com.greensock.TweenLite;
	import com.greensock.easing.Expo;
	import flash.net.navigateToURL;
	import flash.net.URLRequest;

	public class SubNavItem extends Sprite {

		//导航项的名称
		private var _navName:String;
		//导航项的id
		private var _navNum:int;
		//需要跳转到的链接
		private var _toUrl:String;
		//是否选中状态,选中则又灰色背景,没有选中则没有底
		private var _isTag:Boolean = false;
		//底色块
		private var _bg:Sprite=new Sprite();

		//通过构造函数传入相关的值
		public function SubNavItem(name:String = "子菜单项", num:int = 0,toUrl:String="http://www.google.com/",isTag:Boolean=false):void {

			super();

			_navName = name;
			_navNum = num;
			_toUrl = toUrl;
			_isTag = isTag;

			//创建动态文本域
			var t:TextField = new TextField();
			//根据字符数来决定文本域的宽度
			t.width = _navName.length * 15>=60?_navName.length * 15:60;
			t.textColor = 0x959595;
			t.selectable = false;
			t.text = _navName;
			//文本居中对齐
			var tf:TextFormat = new TextFormat();
			tf.align = TextFormatAlign.CENTER;
			t.setTextFormat(tf);
			//根据文本域的宽画一个矩形灰底
			_bg.graphics.lineStyle();
			_bg.graphics.beginFill(0xdcdcdc);
			_bg.graphics.drawRect(0, 1, t.width, 18);
			_bg.graphics.endFill();

			//添加进显示列表
			this.addChild(_bg);

			this.addChild(t);
			//孩子不接受鼠标响应
			this.mouseChildren = false;

			this.buttonMode = true;

			if (!_isTag) {
				//如果不是选中状态的,则不显示背景
				_bg.width = 1;
				_bg.alpha = 0;
				//添加鼠标滑过和滑出监听器
				this.addEventListener(MouseEvent.ROLL_OVER, overSubItem);
				this.addEventListener(MouseEvent.ROLL_OUT, outSubItem);
			}
			//添加点击事件监听器
			this.addEventListener(MouseEvent.CLICK, clickSubItem);

		}
		private function clickSubItem(e:MouseEvent):void {
			//单击发生,通过navgateToURL直接跳转到响应的页面
			trace(this._toUrl);
		}
		private function overSubItem(e:MouseEvent):void {
			//鼠标滑过时,背景缓动出来
			_bg.alpha = 1;
			TweenLite.to(this._bg, .6, { width:this.width, ease:Expo.easeOut } );

		}
		private function outSubItem(e:MouseEvent):void {
			//滑开时,背景缓动收起,收完之后设置透明度为0,使其不可见
			TweenLite.to(this._bg, .6, { width:1, onComplete:setAlpha, ease:Expo.easeOut } );

		}
		//下面要不要没什么关系,如果不考虑获取和存取属性的值
		private function setAlpha():void {
			_bg.alpha = 0;
		}
		public function get navName():String {
			return _navName;
		}
		public function set navName(str:String):void {
			_navName = str;
		}
		public function get navNum():int {
			return _navNum;
		}
		public function set navNum(n:int):void {
			_navNum=n;
		}
		public function get toUrl():String {
			return _toUrl;
		}
		public function set toUrl(str:String):void {
			_toUrl = str;
		}
		public function get isTag():Boolean {
			return _isTag;
		}
		public function set isTag(b:Boolean):void {
			_isTag = b;
		}
	}

}

五、修改文档类,生成二级导航项。

1、首先,我们定义一个数组来保存每个一级导航下面的二级导航(导航项的集合),定义到属性里面:

//定义一个数组来保存每个二级菜单(是菜单项的集合,每个一级导航对应一个二级导航)
		private var _subItemsArr:Array = [];

2、修改xmlLoaded()函数,添加如下的代码:

//定义两个临时变量,用于循环内设置每个菜单项的位置
			var _count:Number;
			var oldWidth:Number;
			//外层循环,循环xml数据中每个top_nav节点
			for (var j:int = 0; j < _navData.top_nav.length(); j++) {

				_subItemsArr[j] = new Sprite();
				//x左边为1000,意思是先不要在舞台上显示
				_subItemsArr[j].x = 1000;
				_subItemsArr[j].y = 39;
				//内层循环,循环每个sub_nav节点
				for (var m:int = 0; m < _navData.top_nav[j].sub_nav.length(); m++) {

					//创建二级菜单项的实例,把相关的值通过构造函数传递过去
					var tempSubItem:SubNavItem = new SubNavItem(_navData.top_nav[j].sub_nav[m].toString(), j * 0 + m, _navData.top_nav[j].sub_nav[m].@link, j==_currentTag&&_subTag==m?true:false);

					if (m > 0) {
						//每个菜单项之间相隔5像素距离,通过_count的累加设置菜单项的x坐标,使每个菜单项依次排开
						_count = _count + oldWidth+5;
					}
					//保存当前这个菜单项的宽度,以在下一次循环中累加
					oldWidth = tempSubItem.width;
					//设置当前菜单项的x坐标
					tempSubItem.x = _count;
					//添加进我们上面定义的数组里面,方便后面的操作
					_subItemsArr[j].addChild(tempSubItem);

				}
				//重置_count
				_count = 0;
				//把这些菜单添加进显示列表
				this.addChild(_subItemsArr[j]);

			}
			//根据_currentTag的值设置当前菜单项的x坐标,坐标的值就是我们xml中设置的coo属性的值
			_subItemsArr[_currentTag].x= _navData.top_nav[_currentTag].@coo;

3、修改outStage()函数,鼠标移出舞台时,还需重置二级菜单的位置,加入如下代码:

				//重置二级菜单的显示与隐藏,通过控制其x坐标达到效果
				_subItemsArr[_overTag].x = 1000;
				_subItemsArr[_currentTag].x = _navData.top_nav[_currentTag].@coo;

4、修改mainNavOver()函数,鼠标滑过各个一级菜单项时,还需控制二级菜单的显示和隐藏:

		private function mainNavOver(e:MouseEvent):void {

			//鼠标在某个菜单项上时,这个菜单项跳转到第二帧
			e.target.gotoAndStop(2);

			//上个二级菜单移到舞台外隐藏起来
			_subItemsArr[_overTag].x = 1000;

			if (_overTag != e.target.id) {

				//上次鼠标所在的菜单项不是本菜单项时,上个菜单项回到第一帧(文字变灰)
				this["nav" + _overTag].gotoAndStop(1);
			}
			//红色块跟随鼠标,滑到响应的菜单项下
			TweenLite.to(this.hover_mc, _easeDelay, { x:e.target.x, ease:ease } );
			//设置_overTag为当前的菜单项id
			_overTag = e.target.id;
			//当前鼠标所在一级导航下的二级导航显示出来
			_subItemsArr[_overTag].x = _navData.top_nav[_overTag].@coo;

		}

到此就完成了本实例的制作,测试看看效果吧。^_^

源代码下载

CKEditor中的字符统计

原文地址:http://www.kuba.co.uk/blog.php?blog_id=20

在CKEditor中统计字符数,去除html标签后的

CKEditor word count

Posted April 30th 2010. Filed under JavaScript.

There are a couple of ways you may want to do this – I’ve described two below. The first is a word count that runs itself and updates a value somewhere on the page, the second a word count initiated by the user.

Method 1: Using a timed function

My solution for the first method is simply a function that runs at a regular interval. It grabs the text from the specific CKEditor instance, performs a word count and updates a div on the page

Stick this function in the head of your document:

function word_count(){
	text_value=CKEDITOR.instances.text_editor_name.getData();
	// make sure to change <B>text_editor_name</B> to the name of your text box!
	var matches = text_value.replace(/<[^<|>]+?>| /gi,' ').match(/\b/g);
	// Nicked the regular expression from an fckeditor example I saw somewhere..
	var count = 0;
	if(matches) {
		count = matches.length/2;
	}
	document.getElementById("word_count").innerHTML=count+" words";
}

Put an element on the page and give it the id ‘wordcount’. Then after your CKEditor element is on the page, put another script tag in and run this:

setInterval ( "word_count()", 5000 );

That should do the job! It will update the word count every 5 seconds

Method 2: Using a CKEditor plugin

To do it this way we’ll need to create a folder in the CKEditor plugins directory. Name it wordcount and create a blank plugin.js file in there. Copy the code below in:

CKEDITOR.plugins.add( 'wordcount',
{
	init : function( editor )
	{
		var pluginName = 'wordcount';

		// Register the command.
		var command = editor.addCommand( pluginName, CKEDITOR.plugins.wordcount );

		// Register the toolbar button.
		editor.ui.addButton( 'wordcount',
			{
				label : "Word count",
				command : pluginName,
				icon: this.path + 'icon.png'
			});
	}
} );

CKEDITOR.plugins.wordcount =
{
	exec : function( editor )
	{
		text_value=editor.getData();
		var matches = text_value.replace(/<[^<|>]+?>| /gi,' ').match(/\b/g);
		var count = 0;
		if(matches) {
			count = matches.length/2;
		}
		alert(count+" words.");
	}
};

You might want to put a nice word count image icon in (icon.png). Here is a lame one I did – just save it into your word count plugin directory: word count icon

When you are initiating your CKEditor you’ll need to add the plugin in, something like this:

var editor = CKEDITOR.replace( 'text_editor_name',
	{
	toolbar : [ [ 'wordcount','-','Save', '-','Bold', 'Italic', 'Underline', 'Strike','-','Maximize' ] ],
	extraPlugins: 'wordcount'
	}
);

You should now have a button in your editor that will give you your word count. Hooray!

======================================

另外,还有个插件http://www.n7studios.co.uk/2010/03/01/ckeditor-word-count-plugin/,可以看看

【酷站】Armani-world

http://www.giorgioarmanibeauty.co.uk/_en/_gb/armani-world/code/index.aspx

loading、过渡很有特点,按钮非常活,视频的应用不少,整站感觉很舒服

下面是loading。。。

【酷站】SOHO阳光

http://www.sohoyg.com

网站表现形式很不错,交互也很流畅,特别是背景音乐,柔和动听啊~~~~~~~~

吸了下来,是AS2的站,应该是建了蛮久的了呵呵

http://u.115.com/file/dn6x3j6t

[转]用AS3的粒子效果创建绚丽的烟花特效

早上在http://www.flashandmath.com/flashcs4/fireworks/看到这个效果,然后就在天地会看到了翻译,翻译很神速哈。效果很不错,转过来

天地会原帖:http://bbs.9ria.com/viewthread.php?tid=89099

=======================================================================

我们带来了一个用成千上万的粒子动画创建的绚丽烟花效果。烟花是由abstract particles创建的,abstract particles它实际上是绘制像素点到一个位图上。为了增强真实感,当烟花绽放时我们点亮了天空,然后动画过程中添加了暗淡的背景。点击屏幕截图或这里的链接,在新窗口打开效果演示。
fireworks.jpg
下载
•        下载该效果的源文件: fireworks.zip
关于代码
在Flash and Math网站我们用到两种类型的粒子。在一些范例里,粒子就是sprite,比如Nova – Cosmic Interactive Particle Effect in AS3 Flash or A 3D Snowfall Effect with Realistic Turbulence and Sense of Depth这些。在其他地方,我们使用了abstract particles,它们不是显示对象。相反,每一个abstract particle就是一些类似位置和速度的集合数据。实际绘制粒子是发生在每一帧循环,利用粒子的位置来绘制到位图上。这种抽象的方法的原因可以看我们的教程Pixel Particles Made Simple – AS3 Flash Tutorial。
为了创建烟花,我们使用了两种类型的abstract particle。”flares”是看不到的粒子-它们在新的烟花被创建时从中心位置爆炸开来。在每一帧,”sparks”会从每个flare的位置发射出去。Spark会绘制到位图里。Flare和spark的移动由一些简单的物理模拟控制,包括重力加速度和空气阻力造成的减速。
为了有助于创建真实的移动。我们使用有着X,Y,X轴和3D矢量速度的3D粒子。然而,为了简化我们不涉及哪些粒子的透视。相反我们在绘制的时候忽略了Z轴方向。这也可以是真实的,因为烟花实际上是远离观测者,透视效果不会被观察到。
我们使用了在我们的一些粒子动画里的简化版粒子类。这里,我们使用的简化Particle3D类只记录很少的一些粒子变量,比如位置,速度,颜色,再加一些控制粒子如何演变的变量。我们也用到了Particle3DList类。这个类关注于储存粒子到一个列表,也包含从列表添加和删除粒子的方法。每当粒子被移除,它们储存到被称为对象池的地方(我们叫它”recycle bin”),以便于再次使用。
颜色是从颜色列表里随机的创建的。一些发白和暗淡的粒子是通过滤镜设置的,请看详细的代码注释。
这样星星只对亮度有所贡献(当背景更亮的时候它们绝不会暗淡无光)。
为了模拟烟花绽放时天空变亮,我们在烟花的下面一层放置了一个黑色的矩形,用ColorTransform来加亮它。亮度值取决于当前移动的粒子数量。我们为它加了一点点淡蓝色。星星放在天空的上一层,并设置它们的blendMode为 “lighten”。
星星由随机的位置和亮度生成,但是通过这种方式来让它们显得比顶层的对象更亮。天际线由一个黑色的MC创建,放在顶层。

无题

近几个月以来,基本上没有怎么闲过,工作太忙了,除了加班还是加班,没办法,公司现在处于一个特殊的阶段,很多东西需要去承担起来,熬过去了,相信会好起来。

因为工作占去了太多时间,学习的计划很多没有完成。一直有关注国外AS3教程的,只是没有足够的时间去把它消化、并转过来。偶尔有个把小时的空闲,即使利用起来,但效率不是很高,主要是因为学习的不连贯性造成的,经常是今天学一点,然后可能要后面两三天甚至四五天才有时间继续之前的学习,这样进度比较慢而且很难做到融会贯通。另外还有一点,人也是需要休息的,忙过头了一有点时间就想什么事都不做,在网上溜达溜达。这种的情况目前是没什么办法解决的,工作一样要完成好,只是希望公司在适合的时候多招几个人来带一带,等他们上手了,我就有多一点的时间来学习我感兴趣的东西,至少下班之后我有点时间。如果每天下班之后都有一两个小时的时间来学习,那学习就没那么不连贯了,效率会上来的。

上面发了点牢骚呵呵,时间虽少,学习虽然很不连贯,但总比不学的好呵呵。断断续续的看完了《The Essential Guide to 3D in Flash》这本书前4章,主要说的是Away3D的基础知识,这本书真的是Away3D的入门好书,强烈推荐!虽然是E文,但作者解说的很通俗易懂,句式都不太复杂,如果有点英文基础,强烈推荐看看这本书。

这几个月另外的一个学习重点就是asp.net了,我以前是用的asp的,做过不少站,但深知asp是一门很落后的网页动态语言了(没有贬义的意思),我们肯定要跟上技术进步的脚步。之前有纠结着学asp.net好还是php好,这两者没有优劣之分,主要看适不适合你。后来考虑到公司服务的大部分企业内部使用的都是asp.net环境的,我们经常需要配合他们做一些网页或者小站,所以就决定学习asp.net了,这是一个原因,其实最主要的还是兴趣,asp.net的神秘和高深一直在吸引着我呵呵。相对于之前的asp建站,asp.net建站与其有很大的不同,它通过对控件的编程、类绑定、数据源绑定等来实现网站的功能,这些东西完全颠覆之前的建站方式。如果用的熟练了,相信建站那是非常轻松的事情,很多代码已经不需要我们亲自一行一行去写了,系统本身就已经实现,我们需要做的只是熟练运用,比如网页里常用的分页技术等等。因为之前有建站的经验(建站的一般流程、理念、可能遇到的问题等,并非asp编程经验),并且有点编程的基础,所以学习asp.net起来感觉还是比较轻松,现在用asp.net来做些小站应该是没问题的。后面熟练一些我再开个asp.net的类别专门发布asp.net的相关文章。

另外呢,早在一两个月前就打算换下网站的皮肤的,托我的朋友Erico.len帮我做平面,但我们两个人最近都很忙,他家里还出了点事,所以一直没有时间来弄,只能先这样了。等我们都稍微有空一点再说。

最后,给自己打打气,加油吧!

[转]HTML5与Flash性能对比

原文地址:http://www.crazyfrom.com/basics/html-div/flash-html5.html

近日,craftymind.com网站向人们证明:HTML5 在性能上仍远远落后于Flashplayer。测试使用了Droid X, Nexus One, Desire HD, Atrix, PlayBook, Galaxy Tab, Xoom 等设备,分别测试他们的位图,矢量图,数值运算,视频播放等项目。

对比得出以下结果:

位图: 所有设备上Flash的位图性能都优于HTML5,平均而言Flash的速度是HTML5的2倍。

矢量图: 所有设备上Flash的矢量图图性能都明显优于HTML5,Flash的速度是HTML5的3到4倍。

数值运算: AS3的确是一种很慢的语言,但那只是相对于Java和C#这些静态语言而言的。不论如今的js得到了多大的优化,都还无法超越支持静态类型的AS3。AS3脚本的速度比js快4倍左右。

视频播放: 这是唯一HTML5胜出的测试内容。播放480p的视频两者都没有问题,但对于720p的Flash视频,仅有Playbook和Xoom可以流畅播放,HTML5在720p视频的播放流畅度上全面超出flash。但随着Stage Video的 普及,以及设备的固件和驱动升级,HTML5的这项优势未必能长久保持。总结:Flashplayer比HTML5快得多,除非是为了支持iOS,否则尽量不要用HTML5开发web游戏和多媒体应用。浏览器开发商似乎也并不关心Canvas2D的性能,他们只关心CSS和SunSpider评分。”

详细的HTML5与Flash性能对比结果请看:GUIMark 3 – Mobile Showdown

18 Free Flash Image Galleries Which Can Be Easily Embedded Into Your Sites

原文地址:http://ntt.cc/2011/05/11/18-free-flash-image-galleries-which-can-be-easily-embedded-into-your-sites.html

We introduced 15+ Free, powerful and easy to integrate Flash image gallery in 2008, it seems has been 3 years ago. And collected 27+ The Best Free Flash Gallery Tutorialsin 2010. Probably some smart readers have built their galleries by themselves. How about you? Here is a new list of free flash image galleries, some of them are listed in the post before, but the new version was released, some of them are new, no matter the older or newer, you can easily embed them into your sites to share your photos or products with very cool effect!

1. 3D Wall Flash Gallery


Using this gallery you have possibility to present your favorite photos in the non-standard way as though they have been placed on art gallery walls.

3D Wall Flash Gallery

2. TiltViewer


TiltViewer is a free, customizable 3D Flash image viewing application, you can customize it via HTML, no Flash IDE needed.

TiltViewer

3. PostcardViewer


PostcardViewer is a free, customizable Flash image viewer. The interface is based on the real world metaphor of a set of postcards shuffled onto a surface.

PostcardViewer

4. Photo Flow Flash Gallery


Use the famous streamline photo flow effect on your website. This effect is well known because of the cover flow gallery switching from iTunes.

Photo Flow Flash Gallery

5. Flash Carousel Slideshow


flShow Carousel is a little Flash movie that you can use to enhance your web pages presenting your images with a nice and stylish carousel effect. It can be used as:

  • a nice photo slideshow
  • an effective product showcase
  • a cool menu for your site

Flash Carousel Slideshow

6. Flash Page Flip Photo Gallery template for Picasa


It is based on the free version of the FlashPageFlip flash engine on flashpageflip.com.

Flash Page Flip Photo Gallery template for Picasa

7. Spread Photo Gallery


Spread Photo Gallery is a Adobe Flash CS3 ActionScript 3 XML photo gallery.

Spread Photo Gallery

8. Polaroid Gallery v.1.01


Polaroid Gallery is a free, opensource flash gallery, this script loads images and image titles dynamically from an external xml file or a flickr RSS feed.

Polaroid Gallery

9. Box Photo Gallery


A natural and compact way to present your photos online. Use the usable table structure of thumbnails for navigating through your online photo gallery.

Box Photo Gallery

10. Circular Gallery


Here is some features of Circular gallery:

- customizable widths and heights for the whole application
- many background and shade properties
- possibility to use images and videos
- the size of the images is customizable as well as the size of the circle
- the text is HTML/CSS formatted
- there are various effects on mouseover and on maximize
- many other features on the Live Demo

Circular Gallery

11. WS Slideshow


WS Slideshow

12. Flash Photo Stack Gallery


Flash Photo Stack Gallery is a simple Photo Gallery for free download.

Flash Photo Stack Gallery

13. Promo Flash Gallery


Easy-to-use photo gallery intended for displaying a range of your products or sequential promo materials.

Promo Flash Gallery

14. Zen Flash Gallery

Zen Flash Gallery author’s design and smart usability make it the most elegant way to present your media content.

Zen Flash Gallery

15. Flash Photo Wall Gallery


Here is some features of the Wall gallery:

- customizable widths and heights for the whole application
- the text is HTML/CSS formatted
- possibility to use FLV video files
- many background and shade properties
- customizable skin for the drag bar
- multiple roll over/out effects
- various options for image expanding
- vertical / horizontal position

Flash Photo Wall Gallery

16. Circular Photo Gallery


Circular Photo Gallery, Flash ActionScript 3.0 XML, rotating thumbnails, fade in/out transitions using Tweener.

Circular Photo Gallery

17. Invent Media Flash PhotoGallery


“Invent Media Flash PhotoGallery” is a free, simple to implement flash photo galley that requires absolutely no Flash or ActionScript skills to implement. You can easily embed it into your site.  The image files are read from an .xml file that can be easily edited using any text editor.

Invent Media Flash PhotoGallery

18. Fish Eye Photo Gallery


Fisheye Image Gallery, Flash ActionScript 3.0 XML, fisheye thumbnails, fade in/out transitions using Tweener, and easy to customize properties.

Fish Eye Photo Gallery

Tweening Tile Photo Gallery in AS3 Flash——加载篇

在上篇教程(Tweening Tile Photo Gallery in AS3 Flash)中用到了一个自定义的加载类GalleryLoader,由于篇幅过长,而且这个类相对独立,所以就重新开了篇博文类专门学习这个类。在GalleryLoader这个类中,又重新定义了另外一个加载类ThumbsLoader,专门用于加载小图的,而GalleryLoader专门用于加载xml数据,提取xml里面的信息。下面先来看看GalleryLoader:

package com.flashandmath.loaders { 

	//导入必要的类
	import flash.display.Loader;

	import flash.display.BitmapData;

	import flash.display.Bitmap;

	import flash.events.EventDispatcher;

	import flash.events.Event;

	import flash.events.IOErrorEvent;

	import flash.net.URLRequest;

	import flash.net.URLLoader;

	//特别注意本类继承自EventDispatcher类,因而就具有调度事件的能力
    public class GalleryLoader extends EventDispatcher {

		//定义几个静态常量,用于标识加载的各个状态
		//ALL_LOADED全部加载完成
		  public static const ALL_LOADED:String = "allLoaded";
		  //xml加载出错
		  public static const XMLLOAD_ERROR:String = "xmlLoadError";
		  //小图加载出错
		  public static const IMGSLOAD_ERROR:String = "imgsLoadError";
		  //xml  URLRequest对象
		  private var xmlRequest:URLRequest;
		  //加载xml变量
		  private var xmlLoader:URLLoader;
		  //存储xml内容的XML对象
		  private var xmlContent:XML;
		  //小图总数
		  private var _numPics:int;
		  //加载是否出错
		  private var isError:Boolean;
		  //存储被加载小图的bitmapData数据
		  private var _bmpDataVec:Vector.<BitmapData>;
		  //存储图片标题
		  private var _capsVec:Vector.<String>;
		  //存储大图地址
		  private var _picsVec:Vector.<String>;
		  //需要加载的小图
		  private var thumbsToLoad:Array;
		  //专门用于加载小图的自定义ThumbsLoader类,讲完这个GalleryLoader类我们再去看ThumbsLoader类
		  private var thumbsLoader:ThumbsLoader;

	     public function GalleryLoader(xml:String){
			 //构造函数获取xml的地址
		     xmlRequest=new URLRequest(xml);

	             }

	   //全局方法loadXML,类外可以调用
	   public function loadXML():void {

		   //定义一个URLLoader用于加载xml
		   xmlLoader=new URLLoader();
		   //侦听加载完成与出错事件
		   xmlLoader.addEventListener(Event.COMPLETE, xmlLoadComplete);

           xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, xmlError);
		   //开始加载数据
		   xmlLoader.load(xmlRequest);

	    }
	   //加载完成处理事件
	   private function xmlLoadComplete(e:Event):void {
		 //取得被加载的XML数据
	     xmlContent = new XML(xmlLoader.data);
		 //移除相关侦听器
	     xmlLoader.removeEventListener(Event.COMPLETE, xmlLoadComplete);

         xmlLoader.removeEventListener(IOErrorEvent.IO_ERROR, xmlError);
		 //处理加载的xml数据
		 procXML();

     }
	 //处理加载到的xml数据函数
	 private function procXML():void {

		 var j:int;
		 //取得xml中定义的tile总数,即图片总数
		 _numPics = xmlContent.tile.length();

		 thumbsToLoad=[];
		 //定义数组长度为_numPics的相关数组
		 //_bmpDataVec存储小图的bitmapData数据
		 _bmpDataVec=new Vector.<BitmapData>(_numPics);
		 //_picsVec存储大图URL地址
		 _picsVec=new Vector.<String>(_numPics);
		 //_capsVec存储图片标题
		 _capsVec=new Vector.<String>(_numPics);

		   for(j=0;j<_numPics;j++){
				 //取得xml中小图的url地址,同时加入预加载数组thumbsToLoad
				 thumbsToLoad.push(xmlContent.tile[j].thumb.toString());
				 //取得大图URL地址
				 _picsVec[j]=xmlContent.tile[j].pic.toString();
				 //取得图片标题
				 _capsVec[j]=xmlContent.tile[j].cap.toString();

			 } 

		 //实例化ThumbsLoader类,专门用于加载小图数据
		 thumbsLoader=new ThumbsLoader();
		 //侦听加载完成事件与出错事件
		 thumbsLoader.addEventListener(ThumbsLoader.IMGS_LOADED,imgsDone);

		 thumbsLoader.addEventListener(ThumbsLoader.LOAD_ERROR,imgsError);
		 //调用ThumbsLoader的loadImgs()方法加载thumbsToLoad数组中的小图队列
		 //ThumbsLoader类的加载过程后面我们再讲
		 thumbsLoader.loadImgs(thumbsToLoad);

	 }

	 private function imgsError(e:Event):void {
		//如果图片加载出错,则发布IMGSLOAD_ERROR事件
		dispatchEvent(new Event(GalleryLoader.IMGSLOAD_ERROR));

	}

	private function imgsDone(e:Event):void {

		 var j:int;
		//加载完成首先移除相关的侦听器
		thumbsLoader.removeEventListener(ThumbsLoader.IMGS_LOADED,imgsDone);

		thumbsLoader.removeEventListener(ThumbsLoader.LOAD_ERROR,imgsError);

			 //循环取得被加载小图的bitmapData数据
			 for(j=0;j<_numPics;j++){
				 //通过clone()方法克隆一个副本存储到_bmpDataVec数组中
				 _bmpDataVec[j]=thumbsLoader.bitmapsArray[j].clone();
				 //调用dispose()方法释放thumbsLoader.bitmapsArray[j]占用的内存
				 thumbsLoader.bitmapsArray[j].dispose();

			 }

		//处理完成,发布ALL_LOADED事件,通知侦听器所有数据已经加载完成
		dispatchEvent(new Event(GalleryLoader.ALL_LOADED));

	}

	private function xmlError(e:IOErrorEvent):void {

		//xml数据加载出错,则发布XMLLOAD_ERROR事件
		dispatchEvent(new Event(GalleryLoader.XMLLOAD_ERROR));

	}

	//通过几个get方法访问本类的私有属性
	//取得被加载小图的原始数据
	public function get bmpDataVec():Vector.<BitmapData> {

		return _bmpDataVec;

	}
	//取得大图地址
	public function get picsVec():Vector.<String> {

		return _picsVec;

	}
	//取得图片标题
	public function get capsVec():Vector.<String> {

		return _capsVec;

	}
	//取得图片总数
	public function get numPics():int {

		return _numPics;

	}

   }

}

下面来看看ThumbsLoader类是如何加载小图队列的:

package com.flashandmath.loaders {
	//导入必要的类
	import flash.display.Loader;

	import flash.display.Bitmap;

	import flash.display.BitmapData;

	import flash.events.Event;

	import flash.events.EventDispatcher;

	import flash.events.IOErrorEvent;

	import flash.net.URLRequest;

	//本类同样继承自EventDispatcher类,因此具有调度事件的能力
    public  class ThumbsLoader extends EventDispatcher {
		  //IMGS_LOADED全局静态常量,标识所有小图是否加载完成
		  public static const IMGS_LOADED:String = "imgsLoaded";
		  //加载是否出错
		  public static const LOAD_ERROR:String = "loadError";
		  //loadersArray数组,即将要被加载的小图队列,从外部通过loadImgs方法传入
		  private var loadersArray:Array;
		  //加载总数
		  private var numImgs:int;
		  //已加载数量
		  private var numLoaded:int;
		  //是否出错
		  private var isError:Boolean;
		  //加载完成之后用于存储小图数据的数组
		  private var _bitmapsArray:Array;
		  //控制加载开关的布尔变量
		  private var loadCanRun:Boolean;
		  //构造函数,打开加载开关
	      public function ThumbsLoader(){

		   this.loadCanRun=true;

	}

	//外部通过调用loadImgs()全局方法把加载队列数组传入本类进行加载
	public function loadImgs(imgsFiles:Array):void {

		   if(loadCanRun){
			//进入加载状态,先关掉加载控制开关
			loadCanRun=false;
			//初始化相关变量
		    numLoaded=0;

			isError=false;
			//取得要加载小图的总数
			numImgs=imgsFiles.length;

		    _bitmapsArray=[];

		    loadersArray=[];

		   for(var i:int=0;i<numImgs;i++){
			  //为每张小图创建Loader对象进行加载
			  loadersArray[i]=new Loader();
			  //侦听每张小图的加载完成事件和出错事件
			  loadersArray[i].contentLoaderInfo.addEventListener(Event.COMPLETE, imgLoaded);

			  loadersArray[i].contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorOccured);
			  //传入URL地址开始加载
		      loadersArray[i].load(new URLRequest(imgsFiles[i]));

		   }

		   }

	}

	private function imgLoaded(e:Event):void {
		//加载完成一次,numLoaded+1;
		numLoaded+=1;
		//下面这个函数检查所有小图是否被加载完
		checkLoadStatus();

	}

	private function errorOccured(e:IOErrorEvent):void {
		//加载出错时。。。。
		isError=true;

		dispatchEvent(new Event(ThumbsLoader.LOAD_ERROR));

	}

	private function checkLoadStatus():void { 

		var i:int;
		//如果已加载的数据等于预加载小图的总数,并且加载过程没有遇到错误,则
		if(numLoaded==numImgs && isError==false){

			 //循环取得加载数组中加载到的图片bitmapData数据
			 for(i=0;i<numImgs;i++){

			  _bitmapsArray[i]=Bitmap(loadersArray[i].content).bitmapData;

		   }
		  //循环移除相关侦听器,并清除数组引用,以让系统回收资源
		  for(i=0;i<numImgs;i++){

			  loadersArray[i].contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, errorOccured);

			  loadersArray[i].contentLoaderInfo.removeEventListener(Event.COMPLETE, imgLoaded);

		      loadersArray[i]=null;

		   }

		   loadersArray=[];

		   loadCanRun=true;
		   //所有数据加载处理完成,发布IMGS_LOADED事件通知侦听器
		   dispatchEvent(new Event(ThumbsLoader.IMGS_LOADED));

		}

	}
	//通过get方法访问_bitmapsArray属性,返回存储小图数据的数组
	public function get bitmapsArray():Array {
		f
		return _bitmapsArray;

	}

   }

}

Tweening Tile Photo Gallery in AS3 Flash

原文地址:http://www.flashandmath.com/advanced/tweengal/index.html

效果地址:http://www.flashandmath.com/advanced/tweengal/TweenTileGallery.html

这是一个非常不错的实例,从这个实例中将学到很多的知识点,比如说victor数组的运用、加载类的编写技巧、对被加载图片的处理等等。本篇文章并不是按原文来翻译,而是一行一行代码的去看,从中学习作者的制作思路和过程,如果有哪里理解错误,欢迎探讨呵呵。

下面的代码是实例TweenTileGallery_CS4.fla源文件中第一帧上面的代码,效果的实现过程基本上都写在了这里,下面开始来学习^^

一、导入必要的类

import fl.transitions.*;
import fl.transitions.easing.*;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Matrix;
import flash.display.Sprite;

import com.flashandmath.objects.Tile;
import com.flashandmath.loaders.GalleryLoader;
import com.flashandmath.preloaders.LoadSpinner2;
import flash.display.Loader;
import flash.display.Shape;
import flash.events.MouseEvent;
import flash.text.TextFormat;
import flash.events.Event;

除了导入系统自带的一些类,还导入了Tile、GalleryLoader、LoadSpinner2三个自定义的类,关于这几个类的具体作用等会用到的地方我在详细说。

二、定义必要的变量

相关说明写到注释里了:

//定义舞台大小
var sw:Number = 780;
var sh:Number = 530;

//实例化一个自定义的类GalleryLoader,这个类的主要作用就是加载本实例中用到的素材,包括xml、图片等。
//关于GalleryLoader类的详细内容请看这边文章http://www.learningas.com/?p=384
var galLoader:GalleryLoader;
//xml中图片的总数
var numPics:int;
//存储所有小图BitmapData数据的Vector数组
var thumbsData:Vector.<BitmapData>
//存储各个小图相对应的大图地址(URL)
var largePicURLs:Vector.<String>;
//存储所有图片的标题
var captions:Vector.<String>;
//定义一个自定义的preloader,相关数据尚未加载完成时将显示
var spinner:LoadSpinner2;

//大图的宽高
var picWidth:Number;
var picHeight:Number;
//每行每列的块数
var divisions:Number;
//块之间的间隙
var gap:Number;
//保存所有块相关信息的Vector数组,Tile为自定义的类,后面会细讲
var tiles:Vector.<Tile>;
//块的宽高
var tileWidth:Number;
var tileHeight:Number;
//定义一个gallery容器
var galleryHolder:Sprite;
//下面几个都是应用缓动时的相关变量
var parameterTween:Tween;
var variationX:Vector.<Number>;
var variationY:Vector.<Number>;
var variationMax:Number;
//是否分拆还是合并状态
var collapsed:Boolean;
//当前被点击小图的索引
var currentPicIndex:int;
//标题显示文本域
var captionBox:TextField;
//分拆、合并缓动的时间
var collapseTweenDuration:Number;
var separateTweenDuration:Number;
var closedPositionOffsetY:Number;
//存储所有小块图片的Vector数组
var thumbnails:Vector.<Bitmap>;
//存储大图的数组,不过我看后面好像没有用到这个变量
var pics:Vector.<Bitmap>;
//存储角度的数组,主要在应用缓动的时候用到
var angles:Vector.<Number>;
//用于加载资源的loader变量
var loader:Loader;
//标识当前是否正在加载
var isLoading:Boolean;
//这个变量也不大明白有什么用,后面有定义了一个值就没用了
var scrollTweenDuration:Number;
//这个变量蛮重要的,就是记录页面的偏移量,现在可能不好理解,后面用到的时候我再详细说。
var pageShift:int;
//块的总数
var numTiles:int;
//总的页数
var numPages:int;
//这个变量也不好解释,下面赋值那里我再说吧~~~
var backSkip:int;
//大图显示后上面显示的上一张图片、下一张图片、返回小图的导航容器。
var navigationPanel:Sprite;

//////////
//舞台不缩放
stage.scaleMode = StageScaleMode.NO_SCALE;

//这个paramObject对象将被用于缓动动画
var paramObject:Object = {t:0};

//创建下一张图片、上一张图片、返回等按钮的实例,这些都是库里面的元件
var btnNextImage:BtnNextImage = new BtnNextImage();
var btnPrevImage:BtnPrevImage = new BtnPrevImage();
var btnNextPage:BtnNextPage = new BtnNextPage();
var btnPrevPage:BtnPrevPage = new BtnPrevPage();
var btnReturn:BtnReturn = new BtnReturn();
var mcViewInstructions:McViewInstructions = new McViewInstructions();

三、初始化

init();

/////////

function init():void {

	//创建相关数组
	thumbsData = new Vector.<BitmapData>();
	largePicURLs = new Vector.<String>();
	captions = new Vector.<String>();
	loader = new Loader();
	//当小图片被点击时用于标识当前是否正在加载的布尔变量
	isLoading = false; 

	//初始化信息框显示内容,提示正在加载...
	infoBox.text = "Loading thumbnails, please wait...";

	//实例化galleryHolder容器
	galleryHolder = new Sprite();
	galleryHolder.x = sw/2 - 3;
	galleryHolder.y = sh/2 + 10;
	this.addChild(galleryHolder);

	//设置相关按钮子对象不响应鼠标事件
	btnPrevImage.mouseEnabled = false;
	btnNextImage.mouseEnabled = false;
	btnReturn.mouseEnabled = false;

	//实例化spinner,加载过程中将会显示。LoadSpinner2为自定义的preloader类,
	//构造函数的两个参数分别为宽和高,setColors可以设置其颜色,bgAlpha为背景透明度
	//设置好相关参数后就调用startSpinner方法显示(转圈)
	spinner = new LoadSpinner2(100,100);
	spinner.setColors(0x000762C5, 0xFF0762C5);
	spinner.bgAlpha = 0.5;
	spinner.x = galleryHolder.x;
	spinner.y = galleryHolder.y;
	this.addChild(spinner);
	spinner.startSpinner();

	//创建GalleryLoader类实例,用于加载xml、小图片,至于本类会单独用一篇文章来说明
	//加载完成之后,可以获取小图的总数、相对应的大图地址、标题、小图位图数据等
	galLoader = new GalleryLoader("gallery.xml");
	//监听的几个事件为GalleryLoader类的自定义的静态全局常量
	galLoader.addEventListener(GalleryLoader.XMLLOAD_ERROR, xmlError);
	galLoader.addEventListener(GalleryLoader.IMGSLOAD_ERROR, imgsError);
	galLoader.addEventListener(GalleryLoader.ALL_LOADED, loadEnded);
	//调用loadXML开始加载数据
	galLoader.loadXML();
}

galLoader侦听的几个事件的处理函数:

//xml加载发生错误时
function xmlError(e:Event):void {
	galLoader.removeEventListener(GalleryLoader.XMLLOAD_ERROR, xmlError);
	galLoader.removeEventListener(GalleryLoader.ALL_LOADED, loadEnded);
	galLoader.removeEventListener(GalleryLoader.IMGSLOAD_ERROR, imgsError);
	infoBox.text="There has been an error loading the XML file. The server may be busy. Try refreshing the page.";
	spinner.stopSpinner();
	spinner.visible=false;
}
//小图加载发生错误时
function imgsError(e:Event):void {
	galLoader.removeEventListener(GalleryLoader.XMLLOAD_ERROR, xmlError);
	galLoader.removeEventListener(GalleryLoader.ALL_LOADED, loadEnded);
	galLoader.removeEventListener(GalleryLoader.IMGSLOAD_ERROR, imgsError);
	infoBox.text="There has been an error loading thumbnails. The server may be busy. Try refreshing the page.";
	spinner.stopSpinner();
	spinner.visible=false;
}
//所有数据加载完成时
function loadEnded(e:Event):void {
	//移除相关侦听器
	galLoader.removeEventListener(GalleryLoader.XMLLOAD_ERROR, xmlError);
	galLoader.removeEventListener(GalleryLoader.ALL_LOADED, loadEnded);
	galLoader.removeEventListener(GalleryLoader.IMGSLOAD_ERROR, imgsError);
	//信息框置空
	infoBox.text = "";
	//spinner停止转动,并设置其不可见
	spinner.stopSpinner();
	spinner.visible = false;
	//进一步初始化,主要是对已加载数据的初步处理
	initApp();
}

四、加载完成之后进一步初始化

function initApp():void {
	//通过galLoader获取图片的总数
	numPics = galLoader.numPics;
	//调用populateVecs()方法把加载得到的数据赋给相应的数组变量
	//function populateVecs():void {
		//var j:int;
		//for(j=0;j<numPics;j++){
			////取得小图的原始数据
			//thumbsData[j]=galLoader.bmpDataVec[j];
			//largePicURLs[j]=galLoader.picsVec[j];
			//captions[j]=galLoader.capsVec[j];
		//}
	//}
	populateVecs();
	//实例化存放小图的数组,注意这个数组存储的是Bitmap类型对象,而thumbsData存储的是BitmapData类型对象
	//两者是有区别的,可参考:http://xiaocui.blogbus.com/logs/30640811.html
	thumbnails = new Vector.<Bitmap>();

	//调用createThumbnailBitmaps()初始化thumbnails数组,主要就是创建小图的Bitmap对象然后存储到这个数组里
	//function createThumbnailBitmaps():void {
		//var i:int;
		//for (i = 0; i < galLoader.numPics; i++) {
			//thumbnails.push(new Bitmap(galLoader.bmpDataVec[i]));
		//}
	//}
	createThumbnailBitmaps();

	//设置大图的宽高
	picWidth = 400;
	picHeight = 300;
	//小图直接的间隙为40
	gap = 40;
	//每行每列的分块数
	divisions = 4;
	//每页的总块数
	numTiles = divisions*divisions;
	//这个变量不大明白其用处,只知道后面在缓动中用了,具体算法搞不大清楚。
	variationMax = 12;
	//总的页数,用总的图片数除以每页的块数(本例是16)然后取整
	numPages = Math.ceil(Number(numPics) / Number(numTiles));
	//下面这个变量的作用其实就是补足小图不足一页的情况,因为效果涉及小图的合并和大图的拆分,如果小图不足一页将会导致错误
	//这个变量可能不好理解,欢迎加我qq探讨99198886
	backSkip = numPages*numTiles - numPics;

	//设置缓动时间
	collapseTweenDuration = 36;
	separateTweenDuration = 30;
	scrollTweenDuration = 40;
	//合并时y轴的偏移量
	closedPositionOffsetY = 0;
	//页码偏移量,后面有设置pageShift += numTiles;即如果当前在第二页,那么pageShift的值就为16
	pageShift = 0;

	//实例化导航按钮的容器,并把相关按钮添加进容器,然后设置其相关属性,比如坐标等
	navigationPanel = new Sprite();
	this.addChild(navigationPanel);
	//开始不让子孩子响应鼠标事件
	navigationPanel.mouseEnabled = false;
	navigationPanel.y = galleryHolder.y + closedPositionOffsetY - picHeight/2 - 40;
	navigationPanel.x = galleryHolder.x + 2;

	navigationPanel.addChild(btnNextImage);
	btnNextImage.y = 0;
	btnNextImage.x = btnReturn.width/2 + 20;

	navigationPanel.addChild(btnPrevImage);
	btnPrevImage.y = 0;
	btnPrevImage.x = -btnReturn.width/2 - 20;

	navigationPanel.addChild(btnReturn);
	btnReturn.y = 0;
	btnReturn.x = 0;
	//设置navigationPanel透明度为零,一开始不可见
	navigationPanel.alpha = 0;

	//mcViewInstructions这个实例是提示浏览者点击小图可以查看大图的MC
	this.addChild(mcViewInstructions);
	mcViewInstructions.y = galleryHolder.y - (picHeight + gap*(divisions-1))/2 - 30;
	mcViewInstructions.x = galleryHolder.x + 3;
	mcViewInstructions.mouseEnabled = false;

	//添加前一页按钮
	this.addChild(btnPrevPage);
	btnPrevPage.x = galleryHolder.x + (picWidth + gap*(divisions-1))/2 + 30;
	btnPrevPage.y = galleryHolder.y - 8;
	//添加下一页按钮
	this.addChild(btnNextPage);
	btnNextPage.x = galleryHolder.x + (picWidth + gap*(divisions-1))/2 + 30;
	btnNextPage.y = galleryHolder.y + 12;
	//侦听相关按钮的点击事件
	btnPrevImage.addEventListener(MouseEvent.CLICK, prevImage);
	btnNextImage.addEventListener(MouseEvent.CLICK, nextImage);
	btnReturn.addEventListener(MouseEvent.CLICK, returnToThumbs);

	btnNextPage.addEventListener(MouseEvent.CLICK, btnNextPageHandler);
	btnPrevPage.addEventListener(MouseEvent.CLICK, btnPrevPageHandler);
	//设置各个按钮的可见状态,很容易理解
	//function setPagingVisibility():void {
		//btnPrevPage.visible = false;
		//btnPrevPage.mouseEnabled = false;
		//btnNextPage.visible = false;
		//btnNextPage.mouseEnabled = false;
		//if (pageShift + numTiles < numPics - 1) {
			//btnNextPage.visible = true;
			//btnNextPage.mouseEnabled = true;
		//}
		//if (pageShift > 0) {
			//btnPrevPage.visible = true;
			//btnPrevPage.mouseEnabled = true;
		//}
	//}
	setPagingVisibility();
	//下面创建存储小块图片的tiles数组,这个数组存放的对象都是Tile类型的,我们来看一下这个自定义的Tile类:
	//package com.flashandmath.objects {
		//import flash.display.Sprite;
		//import flash.geom.Point;
		//
		//public class Tile extends Sprite {
			//public var which:Number;
			//public var openPosition:Point;
			//public var closedPosition:Point;
			//public var color:uint;
			//public var thumbnailHolder:Sprite;
			//
			//public function Tile() {
				//openPosition = new Point();
				//closedPosition = new Point();
				//thumbnailHolder = new Sprite();
				//thumbnailHolder.mouseEnabled = false;
				//this.addChild(thumbnailHolder);
			//}
		//}
	//}
	//Tile类定义了几个全局的属性
	//which用于标识本块属于16块中的第几块,openPosition为拆开后的坐标位置,closedPosition为合并后的坐标位置
	//color为块的颜色,thumbnailHolder为小图存放的容器。
	tiles = new Vector.<Tile>();
	variationX = new Vector.<Number>();
	variationY = new Vector.<Number>();
	angles = new Vector.<Number>();

	//块的宽高
	tileWidth = picWidth/divisions;
	tileHeight = picHeight/divisions;
	//为galleryHolder容器添加阴影滤镜
	var dsf:DropShadowFilter = new DropShadowFilter(6,45,0,0.7,6,6,1);
	galleryHolder.filters = [dsf];
	//初始化标题文本域
	var format:TextFormat = new TextFormat("arial",12,0x000000,false,true);
	format.align = TextFormatAlign.CENTER;
	captionBox = new TextField();
	captionBox.defaultTextFormat = format;
	captionBox.autoSize = TextFieldAutoSize.CENTER;
	captionBox.text = "";
	captionBox.x = galleryHolder.x - captionBox.width/2;
	captionBox.y = 20+galleryHolder.y + 0.5*picHeight + closedPositionOffsetY;
	this.addChildAt(captionBox,0);

	captionBox.mouseEnabled = false;
	//setUpThumbnails()设置小图在Tile中thumbnailHolder容器的坐标和缩放比例
	setUpThumbnails();
	//把块添加到显示列表,并初始化其相关属性,比如拆开、打开后的坐标位置等
	setUpTiles();
	//collapsed为false表示当前为拆分状态
	collapsed = false;
}

下面着重来看看setUpThumbnails()和setUpTiles()两个函数:

function setUpThumbnails():void {
	var k:int;
	//scaleFactor为缩放比例,当小图过大时,将按比例缩小
	var scaleFactor:Number;
	for (k = 0; k < numPics; k++) {
		//tileWidth/thumbnails[k].width计算出比例的值
		scaleFactor = tileWidth / thumbnails[k].width;
		//注意,下面设置的坐标为小图添加到Tile中thumbnailHolder容器里面的坐标
		thumbnails[k].x = -scaleFactor*thumbnails[k].width/2;
		thumbnails[k].y = -scaleFactor * thumbnails[k].height / 2;
		//设置scaleX和scaleY,以保证所有小块图片的大小看起来是一样大的
		thumbnails[k].scaleX = thumbnails[k].scaleY = scaleFactor;
	}
}

function setUpTiles():void {
	//通过两层循环,外层循环表示行数,内层循环表示列数,行列的个数都为divisions,即4个
	for (var i=0; i<= divisions-1; i++) {
		for (var j = 0; j <= divisions - 1; j++) {
			//创建Tile实例对象
			var thisTile:Tile = new Tile();
			//把thumbnails数组中存储的相对应的小图添加进thisTile.thumbnailHolder容器的显示列表中去
			thisTile.thumbnailHolder.addChild(thumbnails[i*divisions + j]);
			//把当前thisTile对象添加进主容器galleryHolder的显示列表
			galleryHolder.addChild(thisTile);
			//计算thisTile的相关坐标,这个坐标的计算还是很好理解的:
			//拿x坐标来说,(picWidth + gap*(divisions-1))/2计算得出galleryHolder容器总的宽度的一半,为负则表示往左的坐标,
			//再加上tileWidth/2(就是块的宽度的一半),再加上间隙(tileWidth+gap)*j就得到了当前thisTile的坐标了。
			//不知道说清楚没有=、=,仔细想一下还是很容易理解的。
			thisTile.openPosition.x = -(picWidth + gap*(divisions-1))/2 + tileWidth/2+(tileWidth+gap)*j;// + (2*Math.random()-1)*gap*0.5;
			thisTile.openPosition.y = -(picHeight + gap*(divisions-1))/2 + tileHeight/2+(tileHeight+gap)*i;// + (2*Math.random()-1)*gap*0.5;
			//下面的计算是合并之后的坐标,主要是去掉了那个间隙的计算
			thisTile.closedPosition.x = -picWidth/2 + tileWidth/2 + tileWidth*j;
			thisTile.closedPosition.y = closedPositionOffsetY - picHeight/2 + tileHeight/2 + tileHeight*i;
			//下面设置thisTile在galleryHolder中的坐标,上面的计算只是存储了左边的值而已,在拆分或者合并时会调用到那些坐标数据
			thisTile.x = thisTile.openPosition.x;
			thisTile.y = thisTile.openPosition.y;
			//设置当前的thisTile为16块中的第几块
			thisTile.which = i*divisions+j;
			//buttonMode为true,鼠标变手型
			thisTile.buttonMode = true;
			//把当前thisTile对象添加到tiles数组,方便后面的操作
			tiles.push(thisTile);
			//设置缓动用到的变量,不是很明白这个计算公式=、=
			variationX.push(4*variationMax*(2*Math.random()-1));
			variationY.push(4*variationMax*(2*Math.random()-1));
			angles.push(0);
			//为每个Tile实例添加侦听器
			thisTile.addEventListener(MouseEvent.CLICK, onTileClick);
		}
	}
}

至此初始化工作完成了,下面就是对于鼠标事件的处理,也是比较难理解的地方。

五、小图单击之后的处理过程

我们首先来看小图单击事件的处理函数onTileClick():

//处理小图单击事件的处理函数
function onTileClick(evt:MouseEvent):void {

	//如果当前正在加载,或者当前就是已合并状态,那么就返回,后续的代码不被执行
	if(isLoading||collapsed){
		return;
	}
	//设置isLoading为true表示当前正在加载图片
	isLoading=true;
	//记录当前单击的小图是哪一块的
	currentPicIndex = evt.target.which;
	//下面这个函数设置上一张、下一张图片按钮的visible和mouseEnabled
	//function setFlipVisibility():void {
		//btnPrevImage.visible = btnPrevImage.mouseEnabled = (currentPicIndex + pageShift > 0);
		//btnNextImage.visible = btnNextImage.mouseEnabled = (currentPicIndex + pageShift < (numPics - 1));
	//}
	setFlipVisibility();
	//spinner可见
	spinner.visible = true;
	spinner.startSpinner();

	//侦听大图的加载完成事件
	loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadComplete);
	loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,loadingError);

	//加载相对应的大图
	loader.load(new URLRequest(largePicURLs[currentPicIndex + pageShift]));

}

大图加载出错的处理函数:

//加载大图出错处理函数
function loadingError(e:IOErrorEvent):void {
	infoBox.text="There has been an error loading the image. The server may be busy. Refresh the page and try again.";
	loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loadComplete);
	loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,loadingError);
	isLoading=false;
	spinner.stopSpinner();
    spinner.visible=false;
}

大图加载完成的处理函数:

function loadComplete(evt:Event):void {
	//移除掉相关加载侦听器
	loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loadComplete);
	loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,loadingError);
	//spinner停止转动并不可见
	spinner.stopSpinner();
	spinner.visible=false;
	//加载状态为false,即加载完成
	isLoading=false;

	//定义一个矩阵,关于矩阵的相信解释请百度、google
	var matrix:Matrix = new Matrix(1, 0, 0, 1);
	//小图位置索引
	var index:int;
	//取得加载的大图原始位图数据
	var bd:BitmapData = Bitmap(loader.content).bitmapData;
	//两层循环开始把大图的数据填充到每个小块里面
	for (var i=0; i<= divisions-1; i++) {
		for (var j=0; j<= divisions-1; j++) {
			//块的索引
			index = i*divisions + j;
			//设置matrix对象的平移坐标
			matrix.tx = (-j-0.5)*picWidth/divisions;
			matrix.ty = (-i-0.5)*picHeight/divisions;

			tiles[index].graphics.clear();
			//用位图填充,通过平移bd图片的位置,从而获取到大图的各个部分图像
			tiles[index].graphics.beginBitmapFill(bd, matrix, false, false);
			//画一个矩形,这个矩形里面填充的就是大图平移后的各个部分的图像
			tiles[index].graphics.drawRect(-tileWidth/2, -tileHeight/2, tileWidth, tileHeight);
			tiles[index].graphics.endFill();
		}
	}

	//显示相对应的图片标题
	captionBox.text = "  "+captions[currentPicIndex + pageShift]+"  "; //adding a little extra space to avoid cutoff
	//如果当前为拆分状态,则调用collapse()函数进行合并
	if (!collapsed) {
		collapse();
	}
}

collapse()合并函数:

function collapse():void {
	//collapsed为true表示当前状态为合并
	collapsed = true;
	//reset the randomization variables so it won't look the same every time:
	//随机产生一些值,用于缓动动画,2*Math.random()-1产生-1到1之间的随机数
	for (var i:int = 0; i < divisions*divisions; i++) {
		variationX[i] = (4*variationMax*(2*Math.random()-1));
		variationY[i] = (4*variationMax*(2*Math.random()-1));
		angles[i] = 60-Math.random()*120;
	}
	//对前面我们定义的paramObject对象的t属性应用缓动,缓动的值从0到1,缓动时间为collapseTweenDuration
	parameterTween = new Tween(paramObject, "t", Elastic.easeInOut, 0, 1, collapseTweenDuration);
	//侦听缓动完成事件
	parameterTween.addEventListener(TweenEvent.MOTION_FINISH, collapseComplete);
	//同事侦听ENTER_FRAME事件,相关的动画效果(比如位移、角度改变等)就是在这个onEnterCollapse处理函数中完成的。
	//不知道作者为什么不用时下流行的Tween类,比如TweenLite等
	this.addEventListener(Event.ENTER_FRAME, onEnterCollapse);
}

function onEnterCollapse(evt:Event):void {
	//相关对象的透明度随paramObject.t值得改变而改变
	captionBox.alpha = paramObject.t;
	navigationPanel.alpha = paramObject.t;
	//1 - paramObject.t表示相反的透明度,如果paramObject.t为1,那么btnNextPage按钮等的透明度就为0
	mcViewInstructions.alpha = 1 - paramObject.t;
	btnPrevPage.alpha = 1 - paramObject.t;
	btnNextPage.alpha = 1 - paramObject.t;

	var quad:Number;
	//下面这个就是动画的过程咯,每帧都会执行一次,paramObject.t是不断改变的,所以产生了动画效果
	for (var i:int = 0; i< divisions*divisions; i++) {
		quad = paramObject.t * (1 - paramObject.t);
		//x,y坐标的改变
		tiles[i].x = tiles[i].openPosition.x + paramObject.t*(tiles[i].closedPosition.x-tiles[i].openPosition.x)+variationX[i]*quad;
		tiles[i].y = tiles[i].openPosition.y + paramObject.t * (tiles[i].closedPosition.y - tiles[i].openPosition.y) + variationY[i] * quad;
		//thumbnailHolder的透明度逐渐变成0,这里存放的是我们原来加载进来的小图,透明度逐渐为0,则大图的相对应部分就会显示出来
		tiles[i].thumbnailHolder.alpha = 1 - paramObject.t;
		//角度的动态改变
		tiles[i].rotation = quad*angles[i];
	}
}

//缓动完成之后触发的函数
function collapseComplete(evt:Event):void {
	//设置标题的位置
	captionBox.x = galleryHolder.x - captionBox.width / 2;
	//移除ENTER_FRAME侦听器
	this.removeEventListener(Event.ENTER_FRAME, onEnterCollapse);
	//侦听galleryHolder的单击事件,单击时将会拆分大图
	galleryHolder.addEventListener(MouseEvent.CLICK, onPicClick);
	//侦听返回小图显示按钮的单击事件
	btnReturn.addEventListener(MouseEvent.CLICK, returnToThumbs);
	//返回按钮响应事件
	btnReturn.mouseEnabled = true;
}

六、大图单击之后的处理过程

在上一步中,当大图显示动画完成之后,我们为galleryHolder添加了鼠标单击事件的侦听器,onPicClick()被触发执行之后,开始对大图进行拆分了。下面我们来看看这个过程。首先先看这两个函数:

function onPicClick(evt:MouseEvent):void {
	btnReturn.removeEventListener(MouseEvent.CLICK, returnToThumbs);
	galleryHolder.removeEventListener(MouseEvent.CLICK, onPicClick);
	separate();
}

function returnToThumbs(evt:MouseEvent):void {
	galleryHolder.removeEventListener(MouseEvent.CLICK, onPicClick);
	btnReturn.removeEventListener(MouseEvent.CLICK, returnToThumbs);
	btnReturn.mouseEnabled = false;
	separate();
}

其实这两个函数是一样的,移除相关侦听器之后开始调用separate()函数进行具体的操作,separate()函数和collapse()函数处理过程非常相似,就不啰嗦注释了。

function separate():void {
	//标识当前状态为拆分状态
	collapsed = false;
	//reset the randomization variables so it won't look the same every time:
	for (var i:int = 0; i < divisions*divisions; i++) {
		variationX[i] = (4*variationMax*(2*Math.random()-1));
		variationY[i] = (4*variationMax*(2*Math.random()-1));
		angles[i] = 60-Math.random()*120;
	}
	parameterTween = new Tween(paramObject,"t",Elastic.easeInOut,0,1,separateTweenDuration);
	parameterTween.addEventListener(TweenEvent.MOTION_FINISH, separateComplete);
	this.addEventListener(Event.ENTER_FRAME, onEnterSeparate);

	btnPrevImage.mouseEnabled = false;
	btnNextImage.mouseEnabled = false;
}

function onEnterSeparate(evt:Event):void {

	captionBox.alpha = 1-paramObject.t;
	navigationPanel.alpha = 1-paramObject.t;
	mcViewInstructions.alpha = paramObject.t;
	btnPrevPage.alpha = paramObject.t;
	btnNextPage.alpha = paramObject.t;

	var quad:Number;
	for (var i:int = 0; i< divisions*divisions; i++) {
		quad = paramObject.t*(1-paramObject.t);
		tiles[i].x = tiles[i].closedPosition.x + paramObject.t*(tiles[i].openPosition.x-tiles[i].closedPosition.x)+variationX[i]*quad;
		tiles[i].y = tiles[i].closedPosition.y + paramObject.t*(tiles[i].openPosition.y-tiles[i].closedPosition.y)+variationY[i]*quad;
		tiles[i].thumbnailHolder.alpha = paramObject.t;
		tiles[i].rotation = quad*angles[i];
	}
}

function separateComplete(evt:Event):void {
	this.removeEventListener(Event.ENTER_FRAME, onEnterSeparate);
}

七、相关按钮的处理函数

//单击上一张图片按钮处理函数
function prevImage(evt:MouseEvent):void {
	//正在加载则返回
	if(isLoading){
		return;
	}
	//标识正在加载.....
	isLoading=true;
	//当前大图显示索引减1,即取得上一张图片的索引
	currentPicIndex -= 1;

	if (currentPicIndex < 0) {
		//pageShift -= numTiles;
		//如果currentPicIndex小于1,则显示上一页的大图了(下面调用prevPage()函数就是进行翻页的)
		currentPicIndex = numTiles - 1
		//有个特殊情况,当前页是最后一页的时候,currentPicIndex需要减掉索引偏移的数值,这个我不知道怎么说清楚=、=
		//大家可以多试验记下就可以明白,或者加我qq探讨99198886
		if (Math.ceil(Number(pageShift)/Number(numTiles)) == numPages - 1) {
			currentPicIndex -= backSkip;
		}
		//进行翻页
		prevPage();
	}
	//重置相关按钮的可见性
	setFlipVisibility();
	//显示spinner
	spinner.visible = true;
	spinner.startSpinner();

	//侦听加载完成事件
	loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadComplete);
	loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,loadingError);

	//加载当前大图
	loader.load(new URLRequest(largePicURLs[currentPicIndex + pageShift]));

}
function prevPage():void {
	var k:int;
	//上一页
	pageShift -= numTiles;
	if (pageShift < 0) {
		pageShift = 0;
	}

	for (k = 0; k < numTiles; k++) {
		//先移除当前所有的小图
		if (tiles[k].thumbnailHolder.numChildren > 0) {
			tiles[k].thumbnailHolder.removeChildAt(0);
		}
		//重新加入新的小图
		tiles[k].thumbnailHolder.addChild(thumbnails[k + pageShift]);
	}
	//重置相关按钮可见性
	setPagingVisibility();
}

单击下一张图片按钮的处理过程也是很类似的,还有其他按钮的单击处理函数,也是很容易理解,就不多啰嗦了:

function nextImage(evt:MouseEvent):void {
	if(isLoading){
		return;
	}
	isLoading=true;

	currentPicIndex += 1;
	if (currentPicIndex > numTiles - 1) {
		//pageShift -= numTiles;
		currentPicIndex = 0;
		//have to do something special if we're on the last page
		if (Math.ceil(Number(pageShift + numTiles)/Number(numTiles)) == numPages - 1) {
			currentPicIndex += backSkip;
		}
		nextPage();
	}

	setFlipVisibility();

	spinner.visible = true;
	spinner.startSpinner();

	//set up listeners for load complete or error, go to changeTilesBeforeCollapse on complete
	loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadComplete);
	loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,loadingError);

	//load image
	loader.load(new URLRequest(largePicURLs[currentPicIndex + pageShift]));

}
function nextPage():void {
	var k:int;
	pageShift += numTiles;
	if (pageShift + numTiles > numPics) {
		pageShift = numPics - numTiles;
	}

	for (k = 0; k < numTiles; k++) {
		if (tiles[k].thumbnailHolder.numChildren > 0) {
			tiles[k].thumbnailHolder.removeChildAt(0);
		}
		tiles[k].thumbnailHolder.addChild(thumbnails[k + pageShift]);
	}

	setPagingVisibility();
}

function btnNextPageHandler(evt:MouseEvent):void {
	nextPage();
}

function btnPrevPageHandler(evt:MouseEvent):void {
	prevPage();
}

===============================================================

至此,本篇实例写完,非常感谢www.flashandmath.com有这么好的教程,本篇实例还涉及两个加载类GalleryLoader和ThumbsLoader没有在这里详细说,关于这两个类的详细说明请看我后面写的这篇文章Tweening Tile Photo Gallery in AS3 Flash——加载篇,也是能从中学到东西的。呵呵