Flash MX 2004中的新组件对于我们开发网络应用程序的确带来了很大的方便,无论是在美观和易使用方面都得到了不错的评价。开发应用程序过程中相信大家使用的比较多的还是基于列表的组件(List、DataGrid、Tree 和 Menu),DataGrid、Tree 和 Menu 组件是 List 类的扩展.下面引用Flash MX 2004帮助文档中的一段描述。
关于 List 类的构成
List 类由行构成。这些行显示滑过和选区突出显示,用作行选区的点击状态,并在滚动中扮演重要的角色。除了选区突出显示和图标(如节点图标和Tree 组件的展开箭头)之外,行还包含一个单元格(或者,如果是 DataGrid,则包含多个单元格)。在默认情况下,这些单元格是实现 CellRenderer API 的 TextField 对象。但是,您可以让 List 使用不同的组件类作为每一行的单元格。唯一的要求是该类必须实现 List 用于与单元格通信的 CellRenderer API。
CellRenderer API 是一组属性和方法,基于列表的组件(List、DataGrid、Tree 和 Menu)使用它们来处理和显示每一行的自定义单元格内容。该自定义单元格可以包含预先建立的组件(如 CheckBox)或您创建的任何类。即我们可以在基于列表的组件中用不同的组件类作为每一行的单元格,在单元格中填入更丰富的内容。Flash MX 2004帮助文档中提到要在单元格中填入不同的组件类我们必须要把作为填充单元格的类实现CellRenderer API。要实现CellRenderer API 我们必须要在此类文件中实现如下四个方法(CellRenderer.getPreferredHeight()、CellRenderer.getPreferredWidth()、CellRenderer.setSize()、CellRenderer.setValue())并且系统将为单元格自动指定两个方法和一个属性(CellRenderer.getCellIndex()、CellRenderer.getDataLabel() 和 CellRenderer.listOwner),以便允许它与基于列表的组件通信。
利用List组件我们可以实现一个列表,让用户选择一个列表中的某个或多个项目,默认情况下列表中的项目只能是文字内容,如果我们想列表中的每一项是一个图片,那是不是会更让用户感兴趣一些。今天我们就用CellRenderer API来实现我们的这个想法。
1、新建一空白文档(尺寸:200 * 150,背景色设为#006600),打开组件面板,从面板中拖一list组件到舞台中并把他的实类名设为myList,宽高分别为160 * 130。保存为LogoAd.fla。

2、在时间轴面板中新建一图层取名为 actions,我们将在这一图层写入我们所需要的所有的actionscript语句。

把不同的内容放在不同的图层并给这些图层取一个和内容相关的名字是一个好习惯。
3、用选择工具选择List组件,下面我们要为List组件设置一些参数,rowHeight 设为128,labels 参数设置如图。

同时请大家准备好5张jpg格式的图片,图片的宽高分别为 128 * 128 ,文件名分别为one,jpg、two.jpg、three.jpg、four.jpg、five.jpg,并且和LogoAd.fla文件在同一目录。在我的源文件中有这样的五张图片,大家可以拿来使用。
4、在单元格中可以放入不同的组件,要在单元格中显示图片,我们可以将loader组件作为单元格的填充,然后在loader组件中装载图片。
5、下面我们来写需要的类文件,如上所述要实现CellRenderer API必须要实现四个方法。为了大家更好的理解每个方法的执行过程,首先在类文件中只写出这四个方法,在函数体内什么都不做。新建一动作脚本文件,写下如下代码:
import mx.core.UIComponent;
class LogoAd extends UIComponent{
//构造函数********************
function LogoAd(){
trace("构造函数执行");
}
function setValue(suggested:String, item:Object, selected:Boolean) :Void{
trace("setValue 方法执行");
trace("suggested 的值是" + suggested);
trace("item 的值是" + item);
trace("selected 的值是" + selected);
}
function setSize(w:Number, h:Number){
trace("setSize 方法执行");
trace(w);
trace(h);
}
function getPreferredHeight(Void) : Number
{
trace("getPreferredHeight 方法执行");
return 128;
}
function getPreferredWidth(Void) : Number
{
trace("getPreferredWidth 方法执行");
return 120;
}
}
然后将此文件保存为 LogoAd.as (文件名一定要与类名相同,大小写也要一样,并且与LogoAd.fla在同一文件夹)。此类扩展了UIComponent类。建议大家以后在写实现CellRenderer API的类时都扩展UIComponent类(UIComponent类扩展自UIObject,而UIObject类又扩展自MovieClip类)。
6、回到LogoAd.fla文件在actions图层的第一帧写下如下语句:
stop();
myList.cellRenderer = "LogoAd";
新建一电影剪辑元件,取名为Logo,在Logo元件上单击鼠标右键选择“链接...”,弹出“链接属性”对话框。在“标识符”文本框中写入“LogoAd”,“AS2.0类”文本框中写入“LogoAd”,其它按默认设置。如图

将LogoAd.fla保存,测试影片。我们可以在输出面板中看到如下输出:
构造函数执行
getPreferredHeight 方法执行
setSize 方法执行
210
128
setValue 方法执行
suggested 的值是one.jpg
item 的值是[object Object]
selected 的值是normal
getPreferredHeight 方法执行
setSize 方法执行
210
128
setValue 方法执行
suggested 的值是one.jpg
item 的值是one.jpg
selected 的值是normal
getPreferredHeight 方法执行
setSize 方法执行
210
128
从上面的输出我们可以看到,CellRenderer API的四个方法自动执行(getPreferredWidth()方法只在Menu 组件中起作用,所以这儿我们并没有看到它执行),构造函数只执行一次,而setSize(),setValue(),getPreferredHeight()方法是每一次渲染都会执行。大家可以拖动list组件的垂直滚动条,就会看到输出面板中setValue(),getPreferredHeight(),setSize()方法依次轮流执行。也就是说list组件只要滚动了或者鼠标移到某个项目上,就要对list组件中的可见项目进行渲染。setSize(w:Number, h:Number)方法带有两个参数,也可以不带参数,如果带参数,在setSize方法执行时参数h的值为getPreferredHeight方法的返回值(这也是为什么getPreferredHeight方法先于setSize方法执行的原因),在setSize方法体内我们么可以对参数w进行引用,w参数的值是list组件的item宽度。在menu组件中参数w的值为getPreferredWidth的返回值。setValue方法设置要显示在单元格中的内容。在执行时,我们可以对它的参数进行引用。说到这儿大家可能对setSize()和setValue()方法不是很理解,没关系,请你继续读下去。理解四个方法的执行顺序对于使用CellRenderer API 很重要,希望大家好好消化。
7、我们需要单元格被loader组件填充,并使用loader组件来载入图片。现在我们需要做的就是修改LogoAd.as文件。修改后的代码如下:
import mx.core.UIComponent;
import mx.controls.Loader;
class LogoAd extends UIComponent{
var loader:MovieClip;
//构造函数*******************
function LogoAd(){
}
function createChildren(){
//创建一loader对象并将返回值赋给变量loader
loader = createObject("Loader","loader",1,{styleName:this, owner:this});
//调用size()函数对loader组件的位置进行初始化
size();
}
function size(Void):Void{
//loader组件的宽高分别为128 * 128
loader.setSize(128 , 128);
//loader组件的初始位置
loader._x = 0;
loader._y = 0;
}
function setValue(suggested:String, item:Object, selected:Boolean) :Void{
//list组件中有item的地方就对单元格进行填充
loader.visible = (item != undefined);
//list组件中有item的地方loader组件就载入相应item内容所指的图片
if(item != undefined){
loader.contentPath = suggested;
}
}
function getPreferredHeight(Void) : Number
{
//因为我们的初始五张图片的宽高分别为128 * 128
//所以这儿将返回值设为128
return 128;
}
}
看了上面的代码后大家发现有很多变化,这些变化是因为考虑到代码的执行效率和条理性才进行改动的。可能疑问最多的就是怎么冒出了一个createChildren()方法。createChildren()是UIComponet类的一个方法,并且在UIComponet类的构造函数内执行。因为LogoAd类扩展了UIComponet类,所以createChildren()方法也是自动执行的。也就是说执行顺序是createChildren(),LogoAd构造函数然后才是CellRenderer API 的四个方法,并且createChildren()方法只执行一次。另外我去掉了setSize()和getPreferredWidth()方法。getPreferredWidth()方法只对menu组件起作用,所以把它去掉。setSize()方法不是一次执行,并且他做的工作没有必要每次渲染的时候都执行这样会消耗cup资源,所以把它去掉。现在解释一下整个执行过程:首先建立一loader对象作为单元格的填充内容(createChildren方法),然后调整loader对象的位置、宽和高(size方法),将size方法放在createChildren中意味着size方法只执行一次,但是只要执行一次就够了。最后在loader组件载入图片,图片地址来自list组件的label值(setValue方法),因为我们预先的五张图片高度是128px,所以将loader组件的最佳高度设为128px(getPreferredHeight方法)。
8、将LogoAd.as文件保存,在LogoAd.fla文件中,在组件面板里将loader组件拖入舞台,然后删掉,测试影片,效果如图。

要理解CellRenderer API的最好方法就是跟着实例一步步地练习,另外对于Flash MX 2004的组件架构要有一定的理解。本教程只涉及到了实现CellRenderer API的一点皮毛知识。对于CellRenderer API更复杂的应用读者可以自行钻研。本人水平有限,文章中可能存在错误,请大家批评指正。
作业:如果图片太大,载入时有一小段时间会出现空白,给加上一个进度条会让用户更愉悦一些。你能加上一个预载进度条吗?
源文件