13
Oct 2009

35首页的Banner印象中是05还是06年写的忘了。当时改过几个版本,有时间控制的,有外部SWF触发,直到后来的帧控制,可谓是经过了不少的“磨难”,从最早的AS到后来的AS2.0,再到现在的AS3.0。

在构思第一版本的时候,中途研究了不少别人写的Flash图片轮播系统,了解其工作原理,所以,最早的版本是根据图片轮播的思路来,由机器生成的时钟点来切换SWF,即通过setInterval来实现,后来的使用过程中发现问题很多,比如网速、内部SWF播放时长等,往往动画还没播完就被强制切换了,最终放弃了这个版本,于是改成外部SWF来触发。

这种做法后来证实挺好用的,唯一不足的是,在做外部SWF的时候需要在最后一帧添加跳转的代码,控制主容器的动作。而由子项去控制父容器的操作,往往都是不受欢迎的,因为不够灵活。而且,当外部动画忘记添加跳转的动作时(比如动画制作人员变更),或者需要加载站外的SWF时,那问题就又出现了,风险还是挺大的,于是决定转换思路,将主容器的控制由被动转主动,监听外部SWF的播放情况来控制内容切换,到目前为止,这种思路还未发现问题,所以,此次的AS3.0的改版就是基于这个思路之上。

讲了这么多版本的历史及优缺点,现在咱来讲讲AS3.0的代码结构,俺们先来看张简图:
pic
整个调用的处理都是由AS3.0提供的监听事件来完成,传闻AS3.0的监听机制很牛X,目前为止仅使用到现阶段,不好说什么。

为了方便下文,再来看看被载入的数据结构:
a
首先,为了让整个数据处理得更顺畅些,在原始数据刚被载入的时候就进行相应的预处理,进行数据筛选分组,以便使所有的数据看起来更有序。在载入数据的时候,AS3.0提供了比以往版本更加灵活的方法,如果被载入的数据是结构完整的XML数据,则其会直接将XML的节点当做XML对象的属性来使用,大大简化了XML的操作方法。

仅仅两句代码就结束了XML数据的读取:

  1. 1
  2. 2
  1. var xml:XML = new XML(xmlLoader.data);
  2. var node:XMLList = xml.child("banner")//这个banner就是XML的节点

预处理的方法如下:

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  1. for(var n = 0, len = node.length(); n < len; n++){
  2.  xmldata.push({
  3.   path : node.path[n],
  4.   txt: node.txt[n],
  5.   link : node.link[n],
  6.   target : node.target[n]
  7.  });
  8. }

其中,为了方便其他方法能顺畅地调用这个处理后的数据,这里使用全局的数组对象xmldata。

再根据这个处理后的数据集,生成供用户随时切换的按钮集合:

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  1. for(var s = 0, nodes = xmldata.length; s < nodes; s++){
  2.  var index:int = s + 1;
  3.  var btn_mc:MovieClip = new btn()//库元素中创建的影片剪辑,有两帧,分别表示按钮的两种状态。
  4.  btn_mc.buttonMode = true;
  5.  btn_mc.current = s;
  6.  CreateNumText(index, btn_mc)//该方法为动态创建标签编号,使用TextField的方法实现。
  7.  btn_mc.addEventListener(MouseEvent.CLICK, AttachMouseClick)//为按钮添加监听点击的动作
  8.  btn_mc.x = 25 * index;
  9.  btn_mc.y = screen.stage_height - 25;     
  10.  btn_collection.push(btn_mc)//为了方便其他方法对按钮的状态进行处理,将创建好的按钮存放到数组中。
  11.  removeEventListener(MouseEvent.CLICK, arguments.callee)//移除监听
  12.  addChild(btn_mc)//将新实例出来的按钮添加到主场景中
  13. }

然后加载外部动画,代码结构看起来好像有点山寨,但逻辑我想应当很容易看出来。

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  1. //创建载入动作条,在载入较大的动画时不至于让用户感觉浏览器当机
  2. loadBar.graphics.beginFill(0xff0000);
  3. loadBar.graphics.drawRect(0,screen.stage_height - 2,1,2);
  4. loadBar.graphics.endFill();
  5. addChild(loadBar);
  6.  
  7. //获取场景中播放动画使用的容器,由于目前场景只有一个播放的容器MC,所以直接使用getChildAt(0)来转换。
  8. var mc:MovieClip = getChildAt(0) as MovieClip;
  9. var path:String = xmldata[index].path//从预处理后的数据集中调取需要用到的数据,这里的index为播放索引
  10. var loader:AVM2Loader = new AVM2Loader();   //使用动态重写Loader方法,由libspark.org(1)提供。
  11. //var loader:Loader = new Loader();
  12. loader.load(new URLRequest(path));
  13.  
  14. //添加各类监听操作,包括即时跟踪外部动画的大小,载入情况等。
  15. loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, LoadProgress);
  16. loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(evt:Event){
  17.  mc.addChild(loader);
  18.  var new_mc:MovieClip = MovieClip(evt.currentTarget.loader.content);
  19.  current_mc = new_mc; 
  20.  var url:String = xmldata[index].link;
  21.  var win:String = xmldata[index].target;
  22.  if(url != ""){ //当Link项不为空的时候,为影片剪辑添加鼠标点击动作。
  23.   if(win == ""){
  24.    win = "_self";
  25.   }
  26.   new_mc.buttonMode = true;
  27.   new_mc.addEventListener(MouseEvent.CLICK, function(){
  28.    navigateToURL(new URLRequest(xmldata[index].link), win);
  29.   });
  30.   new_mc.removeEventListener(MouseEvent.CLICK, arguments.callee)//移除鼠标监听动作
  31.  }
  32.  new_mc.addEventListener(Event.ENTER_FRAME,EnterFrame)//监听外部SWF的播放情况
  33.  removeChild(loadBar);
  34.  loader.removeEventListener(ProgressEvent.PROGRESS, arguments.callee);
  35.  loader.removeEventListener(Event.COMPLETE, arguments.callee);
  36. });

与载入外部动画有关的相关方法:

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  1. //监听外部SWF的载入情况
  2. private function LoadProgress(evt:ProgressEvent){
  3.  var loaded:int = evt.bytesLoaded;
  4.  var total:int = evt.bytesTotal;
  5.  var scaleWidth:int = (loaded * screen.stage_width) / total;
  6.  loadBar.scaleX = scaleWidth;
  7. }
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  1. //监听外部SWF的播放情况
  2. private function EnterFrame(evt:Event):void{
  3.  var mc:MovieClip = evt.target as MovieClip;
  4.  trace("thread" + test_index + ": " + mc.currentFrame + "total: " + mc.totalFrames);
  5.  if(mc.currentFrame == mc.totalFrames){
  6.   s_index ++;
  7.   if(s_index >= btn_collection.length){
  8.    s_index = 0;
  9.   }
  10.   LoadNewSwf(s_index);
  11.   mc.removeEventListener(Event.ENTER_FRAME, arguments.callee)//播放完成之后移除监听
  12.  }
  13. }

整个Banner的架构大致就是这样的,当然,在编写的过程中,相关的方法注意引用进来,以免造成方法或对象无法使用的问题,这里我使用了以下包:

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  1. import flash.display.Sprite;
  2. import flash.display.Stage;
  3. import flash.display.Loader;
  4. import flash.display.Shape;
  5. import flash.display.Graphics;
  6. import flash.display.MovieClip;
  7. import flash.display.LoaderInfo;
  8. import flash.xml.*;
  9. import flash.net.URLLoader;
  10. import flash.net.URLRequest;
  11. import flash.net.navigateToURL;
  12. import flash.text.TextField;
  13. import flash.utils.*;
  14. import flash.events.*;
  15. import com.ubbcn.*//自制包,包含AVM2Loader的方法及其他必要对象。

在编码的过程中碰到不少问题,其中,最大的问题应当就是不同版本的SWF被AS3.0加载进来时制式(2)转换的问题了,AS3.0的制式是AVM2,而之前的版本均是AVM1,很令人抓狂。就这个问题当时处理了好几天也没搞定。当然,现阶段使用的是Hack的方法大致处理好了,但就我个人看来还是没有完美解决,问了不少人,都说这个暂时没办法,版本限制死了,只能在制作外部SWF时注意一下发布的版本。

注(1):AVM2Loader方法是使用别人Hack的方法,具体的代码及使用方法可以移步:http://www.libspark.org/wiki/fladdict/AVM2Loader,这里先感谢一下这些不知名的作者们。
注(2):制式这个词不知道这里使用合不合适,暂时没有找到更贴切的描述。

 

PS:此篇文章应部分网友要求特别编写,如需转载请注明转自ui.35.com。

好东西我们会尽可能的和大家一起分享,同时也请转载时尊重下我们的劳动付出,谢谢~~!

推荐(1)
收藏

网友评论:

  1. Juns 说:

    强大的35.comBanner终于解密了!! :grin:

    [回复]

  2. SOS 说:

    :lol: 好复杂,有点看不懂了。

    [回复]

  3. 灯心草 说:

    :evil:
    呃。。研究研究。。

    [回复]

    撒啊分 回复:

    还行

    [回复]

发表评论: