创建Flash CS3组件(四) 编写组件类

来源:互联网 发布:京东刷单软件 编辑:程序博客网 时间:2024/05/02 00:31

创建Flash CS3组件(四) 编写组件类
在上一讲,我们已经决定好的组件的外观与样式,现在,我们要做的是规划组件类.
用户设定组件,靠得就是组件的方法与属性,一个组件应当有什么属性,什么方法,这也是一个需要仔细规划的方面,规划的原则当然也是以需求为先.

1.Accordion组件的属性
(1)首先,我们希望用户可以通过一个属性统一设定组件的子项,这个属性就是数据提供者,一般命名为dataProvider,这个属性应该是一个数组,数组的每个项都是一个对象.由于我们希望用户可以自定义图标,所以这个对象需要有label,icon,data三个属性,分别代表标题按钮的标签,图标和对应的显示对象.而我们还想使用元数据中的Collection 标签来方便用户,于是,我们仿照fl.data.DataProvider类建立一个自己的类:com.cyjb.data.ChildrenProvider,并建立了一个对应的Item类:com.cyjb.data.ChildrenProviderItem.对于这两个类,我不做过多介绍,具体的可以自己看类代码,有很详细的注释.
(2)其次,我们希望用户可以检索添加的子项个数,于是我们需要一个length属性.
(3)用户当然希望知道组件的那个子项被选择了,而且可能会想与被选择的子项进行交互,所以我们要添加两个属性:selectedIndex和content,分别是选择的索引和对子项的引用.

2.Accordion组件的方法
Accordion组件的方法比较简单,肯定都是用来添加或删除子项的,所以只定义八个方法:
addItem(item:Object):void
addItemAt(item:Object,index:uint):void
getItemAt(index:uint):Object
removeItemAt(index:uint):Object
removeItem(item:Object):Object
removeAll():void
replaceItem(newItem:Object,oldItem:Object):Object
replaceItemAt(newItem:Object,index:uint):Object
当然,方法看起来多,但是实现起来都很简单.我们根据dataProvider属性的改变来更改子项,所以只要把上面八个方法直接连接到ChildrenProvider类的相应方法中去就可以了.

3.Accordion组件应该如何工作
我们用LabelButton作为标题栏按钮,然后将所有标题栏按钮都放在一个Sprite中,将导入的子项放在另一个Sprite中,并利用ScrollRect来设置遮罩.
因为当ChildrenProvider类发生更改时会广播dataChange事件,所以我们监听这个事件,并调用invalidate(InvalidationType.DATA),使组件在下一次刷新时一起绘制,以节约资源.

4.真正开始编写Accordion类
(1)编写类的大致框架
首先,我们把已经规划好的部分搭建成一个类框架,然后再把真正的代码一点点的嵌入这个框架中.
完成了的类框架

(2)组件的构造函数
在这里,我们要初始化所有变量
public function Accordion():void{
 //记得super(),最好放在开头,先初始化UIComponent的变量,防止出现问题
 super();
 _contains = [];
 headerList = [];
 if(_dataProvider == null){
  //这里为什么要用dataProvider而不是_dataProvider?
  //因为组件要监听dataProvider的事件,
  //直接设定dataProvider更符合代码重用的概念
  dataProvider = new ChildrenProvider();
 }
}

(3)configUI函数
override protected function configUI():void{
 //初始化容器
 headers = new Sprite();
 container = new Sprite as DisplayObject;
 addChild(headers);
 addChild(container);
 //不在这里初始化background,因为要在drawBackground函数中设置
 super.configUI();
}

(4)draw函数
这里是组件的核心,需要详细说明.
我们的组件可能发生重绘的部分是SZIE,STYLES,DATA,SELECTED
当SZIE和hederHeight,contectPadding样式发生改变时,我们需要重新排列所有的内容.
当STYLES发生改变时,我们会重新绘制所有标题按钮和重绘背景.
当DATA发生改变时得删掉多余的标题按钮并且新建更新的标题按钮,在这里仅仅使用一种很简单的算法,虽然它比较浪费内存,但是我们的目的是学习组件类的编写.
当SELECTED发生改变时,也是重新排列标题按钮的位置,我们会把它与SZIE一同考虑.
override protected function draw():void{
 //样式发生了改变
 if (isInvalid(InvalidationType.STYLES)) {
  //绘制背景
  drawBackground();
  //刷新标题按钮的样式
  updateHeaderStyles();
  //如果需要更改SIZE的话
  var hh:Number = Number(getStyleValue("headerHeight"));
  var cp:Number = Number(getStyleValue("contentPadding"));
  if((hh != headerHeight)||(cp != contentPadding)){
   headerHeight = hh;
   contentPadding = cp;
   //注意,还是使用invalidate()
   invalidate(InvalidationType.SIZE);
  }
 }
 if (isInvalid(InvalidationType.DATA)) {
  //绘制标题按钮
  drawHeader();
 }
 if (isInvalid(InvalidationType.SIZE,InvalidationType.SELECTED,InvalidationType.DATA)) {
  //排列按钮
  drawLayout()
 }
 super.draw();
}
在组件类的书写中,在任何情况下使用invalidate()而不是直接调用方法都是一个好习惯,invalidate()方法可以尽可能的帮助你减少资源浪费.
在draw中,判断InvalidationType是有顺序的,尽量使工作不会重复进行.例如,在Accordion中,drawHeader()会设置标题按钮的style,而updateHeaderStyles()做的是同样的工作,于是我们就先判断InvalidationType.STYLES,减少浪费.
其次,是将专门干某一项工作的一些代码封装成方法,这样不但是代码易于理解,还会方便修改.而且,如果要作为基类扩展的话,会大大减少子类的工作量.
还有,无论如何,更改样式都是一个相当浪费的事,所以尽可能的减少对style的更改.但是,如果想减少对style的更改,就需要在draw中做更多判断,反而不利于阅读和执行效率,这是一个矛盾,需要仔细考虑.

(5)其它方法
对于其它的方法就不做特别的说明了,大家可以自己看类代码.
基本完成的组件

到目前为止,组件几乎已经完成了,但是,还缺少很重要的一点,也是只有组件才具有的一点特性:实时预览.
在下一节,我会详细的说明该如何制作一个完美的实时预览.

原创粉丝点击