利用XML动态创建类

这是一个很好用的技术,我已经在As3中使用它好长一段时间了。使用之前最基本的条件是,你已经知道了类的名字和所属包的的路径,这样就可以轻而易举的在运行时创建类。那么为什么需要这么做呢?有两种情况:一是你有从外部的swf导入的类,二是你已经编译了所有的类,却还想按照XML的配置改变其中的一些类,又不想重新编译。当你用一种CMS生成了你的站点,那么这也是一个非常好用的技术。想象一下,可以把类用于CMS的一段中(a section in the CMS),并且允许编辑从一套“类模板”中选取所需要的。现在,我们有一些在某些地方使用的例子,一起看看我们是如何轻松实现它的。

第一步:创建一个测试类

第一件事情,我们需要做的是创建一个测试类。在你的项目中,创建一个包路径为com.flashartofwar.example的类,如下所示:

  1. package com.flashartofwar.example {
  2.          import flash.display.Sprite;
  3.          /**
  4.           * @author jessefreeman
  5.           */
  6.          public class RedBox extends Sprite {
  7.                   
  8.                   protected var _width:Number = 0;
  9.                   protected var _height:Number = 0;
  10.                   
  11.                   /**
  12.                    * We override the public setter for width so we can redraw
  13.                    * the box when the width is changed.
  14.                    */
  15.                   override public function set width(value : Number) : void {
  16.                            _width = value;
  17.                            trace("Width", super.width);
  18.                            redraw();
  19.                    }
  20.   
  21.                   override public function get width() : Number {
  22.                            return _width;
  23.                    }
  24.   
  25.                   /**
  26.                    * We override the public setter for width so we can redraw
  27.                    * the box when the width is changed.
  28.                    */
  29.                   override public function set height(value : Number) : void {
  30.                            _height = value;
  31.                            redraw();
  32.                    }
  33.   
  34.                   override public function get height() : Number {
  35.                            return _height;
  36.                    }
  37.   
  38.                   public function RedBox() {
  39.                            width = 100;
  40.                            height = 100;
  41.                            redraw();
  42.                    }
  43.                   
  44.                   /**
  45.                    * This simply clears the graphics and redraws the box based
  46.                    * on the new width and height.
  47.                    */               
  48.                   public function redraw():void
  49.                   {
  50.                            graphics.clear();
  51.                            graphics.beginFill(0xFF0000);
  52.                            graphics.drawRect(0, 0, width, height);
  53.                            graphics.endFill();
  54.                    }
  55.           }
  56. }
复制代码

就像你看到的,这个基本的类继承了Sprite,并添加了管理width/height的自定义逻辑,还画了一个shape。我不愿将更多的时间花费在这个类上,它只是一个最基本的例子,任何的类都可以在这里良好的运行。

第2步:建立一个Doc类

现在我们需要一个文档类,来测试我们的RedBox类是否工作。

  1. package {
  2.          import flash.display.StageAlign;
  3.          import flash.display.StageScaleMode;
  4.          import com.flashartofwar.example.RedBox;
  5.          import flash.display.Sprite;
  6.          /**
  7.           * @author jessefreeman
  8.           */
  9.          public class DynamicClassDemo extends Sprite {
  10.                   public function DynamicClassDemo() {
  11.                            configureStage();
  12.                            createRedBox();
  13.                    }
  14.                   
  15.                   private function configureStage() : void {
  16.                            stage.scaleMode = StageScaleMode.NO_SCALE;
  17.                            stage.align = StageAlign.TOP_LEFT;
  18.                    }
  19.   
  20.                   private function createRedBox() : void {
  21.                            var redBox:RedBox = new RedBox();
  22.                            redBox.width = 100;
  23.                            redBox.height = 100;
  24.                            redBox.x = redBox.y = 10;
  25.                            addChild(redBox);
  26.                    }
  27.           }
  28. }
复制代码

同样,这个类也没什么特殊的。我设定了下stage,并建立一个可以创建RedBox的类。如果你运行下,你会看到一个100×100的红色的盒子。到这为止呢,所有的事情看起来都是这么的正确。

第三步:使用getDefinitionByName
接下来,让我们尝试下动态创建RedBox类。我将要使用到一个叫做getDefinitionByName的包方法,它可以通过完整的包路径和类名来查找某个类。把createRedBox方法用以下的代码替换。

  1. private function createRedBox() : void {
  2.          var tempClass : Class = getDefinitionByName("com.flashartofwar.example.RedBox") as Class;
  3.          
  4.          var redBox:RedBox = new tempClass();
  5.          redBox.width = 100;
  6.          redBox.height = 100;
  7.          redBox.x = redBox.y = 10;
  8.          addChild(redBox);
  9. }
复制代码

你也要导入如下:

  1. import flash.utils.getDefinitionByName;
复制代码

好,注意到了吗?我们这里只是简单地用new tempClass()替换了new RedBox(),并在这行之前使用了getDefinitionByName方法。只有这一点改变。我们建立了一个Class类型的持有变量,然后用getDefinitionByName返回了一个com.flashartofwar.example.RedBox类的实例。一旦我们有了一个类自己的引用,那么我们就可以简单地创建新的实例。灵巧的技巧,对吧?同样,我们若不使用As3自己的internal类去到系统里找我们所需要的类,这样写也是可以的,var tempClass:Class =com.flashartofwar.example.RedBox。运行一下,你同样可以看到一个和第2步相同的红色的盒子。
让我们通过XML来创建类吧,你可能会惊讶它有多么简单哦!

第四步:通过XML创建RedBox
现在我们要做与第三步同样的事情,只不过要把类的名字放到XML里。在这里例子里我要做些令人兴奋的

小变化。为什么你不用下面的代码再一次代替createRedBox呢?

  1.          // This is some sample XML data, we can just as easily
  2.          // loda this at runtime instead of compiling it in.
  3.          var xmlData:XML = <boxes base-package="com.flashartofwar.example">
  4.                  <box name="box1" class="RedBox" x="10" y="10" width="100" height="100"/>
  5.                  <box name="box2" class="RedBox" x="120" y="10" width="50" height="100"/>
  6.                  <box name="box3" class="RedBox" x="190" y="10" width="20" height="100"/>
  7.          </boxes>;
  8.          
  9.          // Pull out some core data we need from the xml
  10.          var basePackage:String = xmlData.@["base-package"];
  11.          var boxes:XMLList = xmlData.*;
  12.          var box:XML;
  13.          var boxInstance:DisplayObject;
  14.          
  15.          // Loop through each box node and build it's class
  16.          for each(box in boxes)
  17.          {
  18.                   // It is very important that we use quotes for the class
  19.                   // because it is a reserved word
  20.                   var tempClass : Class = getDefinitionByName(basePackage+"."+box.@["class"]) as Class;        
  21.                   // Here we type box to DisplayObject since we are not
  22.                   // sure what class it actually is
  23.                   boxInstance = new tempClass();
  24.                   boxInstance.x = Number(box.@x);
  25.                   boxInstance.y = Number(box.@y);
  26.                   boxInstance.width = Number(box.@width);
  27.                   boxInstance.height = Number(box.@height);
  28.                   
  29.                   addChild(boxInstance);
  30.           }
  31. }
复制代码

确定你要导入了下面的代码哦:

  1. import flash.display.DisplayObject;
复制代码

这回,我们有很多事情要做了,我添加了一些注释来帮助你。在上面的代码中,我们写了一些xml,并循环每一个box结点。一个好的技巧是,为了减少重复性得写代码,把package名字作为根结点的属性。下一步,你会看到每一个box都有一个名字、一个类、一个x值、一个y值,宽度和高度。最后的事情是,你应该注意我把redBox变量改成boxInstance,并且它现在的类型是DisplayObject类型的。运行下,看看发生了什么。

哦!你会看见如下的错误:

  1. ReferenceError: Error #1065: Variable RedBox is not defined.
  2.         at global/flash.utils::getDefinitionByName()
  3.         at DynamicClassDemo/createRedBox()
  4.         at DynamicClassDemo()
复制代码

在没有定义类型之前,它不再是com.flashartofwar.example.RedBox的引用,所以编译器会忽略导入它。这是在通过XML动态创建class的时候经常出的一个问题,我们不得不要使用一些技巧强制编译器包括这个类。让我们在com.flashartofwar.example包中创建一个叫做IncludeClasses 的新类:

  1. package com.flashartofwar.example {
  2.          /**
  3.           * @author jessefreeman
  4.           */
  5.          public class IncludeClasses {
  6.                   RedBox;
  7.           }
  8. }
复制代码

我知道,你一定认为这太疯狂了吧,但是这就是解决动态创建类的方法。非常简单地把类名字放进一个空类里,编译器就是加载它,即使在这个类里面没有任何的变量被定义。最后的事情是,定义一个该类的变量放到我们的文档类里。这里是代码:

  1. // This class forces the compiler to import your dynamic Classes
  2. var includeClasses:IncludeClasses;
复制代码

并确定你导入了这个:

  1.   
  2. import com.flashartofwar.example.IncludeClasses;
复制代码

现在再次运行你的项目,你会看到3个盒子通过XML动态得被初始化出来。这可不简单哦,你可以自己试着创建一个类,来创建绿盒子和蓝盒子,然后把它们加入到IncludeClasses类里面,然后再在XML文件中配置一下。他们会像红盒子这样被创建出来。当我们知道包路径和类名的时候,我希望使用getDefinitionByName的这个简单的例子可以让我们更简便地创建类。请在评论里自由的发言吧,并讨论你在自己的项目中是如何使用这个技巧的呢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值