定制Tree 的外观
Flex 中的Tree是mx前缀的组件,spark组件中没有替代品。
以下解决Flex4 项目中外观的定制化。
更换背景
backgroundColor 和 backgroundAlpha两个样式属性无法在flex4的项目中使用。替代的只有一个属性:contentBackgroundColor,没有找到背景透明度的相关设置功能。
更换图标
图标包括叶子节点的图标、分支节点的图标、分支节点的打开关闭图标
需要分别设置:defaultLeafIcon、folderClosedIcon、folderOpenIcon、disclosureClosedIcon、disclosureOpenIcon属性,它们的值需要是绑定的图标文件Class。
定制项内容
指定Tree的项渲染器,项渲染器要以MXTreeItemRenderer扩展。
<?xml version="1.0" encoding="utf-8"?>
<s:MXTreeItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" height="55"
>
<fx:Script>
<![CDATA[
override public function set data(value:Object):void {
super.data = value;
if(treeListData.hasChildren)
{
setStyle("fontWeight", 'bold');
labelField.text = treeListData.label;
}
else
{
setStyle("fontWeight", 'normal');
labelField.text = treeListData.label;
}
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="hovered" />
<s:State name="selected" />
</s:states>
<s:Rect left="0" right="0" top="0" bottom="0">
<!--填充颜色-->
<s:fill>
<s:SolidColor color="0x0" alpha="0.85" />
</s:fill>
</s:Rect>
<s:HGroup left="0" right="0" top="0" bottom="0" verticalAlign="middle">
<s:Rect id="indentationSpacer" width="{treeListData.indent}" percentHeight="100" alpha="0">
<s:fill>
<s:SolidColor color="0xFF0000" alpha="1" />
</s:fill>
</s:Rect>
<s:Group id="disclosureGroup">
<s:BitmapImage source="{treeListData.disclosureIcon}" visible="{treeListData.hasChildren}" />
</s:Group>
<s:BitmapImage source="{treeListData.icon}" />
<s:Label id="labelField" color="#FFFFFF" fontSize="18" text="{treeListData.label}" paddingTop="2"/>
</s:HGroup>
<s:Line left="10" right="10" bottom="0">
<s:stroke>
<s:SolidColorStroke color="0x505050"/>
</s:stroke>
</s:Line>
</s:MXTreeItemRenderer>
控制项间隙
需要指定Tree的paddingBottom和paddingTop 属性。
如果不需要间距可以将他们都设置为0。
指定Tree的纵向滚动条皮肤
需要指定Tree的verticalScrollBarStyleName,他是一个样式名称。
一个没生效的做法
.MyStyleName
{
skinClass:ClassReference("skins.bookdetailVScrollBar.BookDetailVScrollbarSkin")
}
其中的皮肤类修改自spark VScrollBarSkin,其中指定了滑轨、滑块、上下按钮的样式。
这个方法不生效,原因未知。
一个可行的方法
.MyStyleName
{
downArrowSkin: ClassReference(null);
upArrowSkin: ClassReference(null);
trackSkin:ClassReference("skins.bookdetailVScrollBar.BookDetailVScrollBarTackSkin");
thumbSkin:ClassReference("skins.bookdetailVScrollBar.BookDetailVScrollBarThumSkin")
}
这个样式写法中,指定了滚动条的四个部分。其中上下按钮不需要,注意他们的写法。
背景透明(spark)
contentBackgroundAlpha=”0”
只保留了渲染项的内容和边框。
背景颜色(spark)
contentBackgroundColor
渲染项颜色和背景的关系处理
背景有时候会超过所有渲染项的高度,如果二者颜色不同,看起来非常不舒服。所以可以设置背景颜色,渲染项多数内容透明。
选中项颜色
selectionColor
鼠标经过项颜色
rollOverColor
给Tree提供数据源
采用ArrayCollection
多级数据需要有“children ”属性,其内容应该是该项的子项内容。
控制Tree的展开闭合
方法
expandChildrenOf
expandItem
判断是否开合
isItemOpen
属性
openItems
可以是数组。将其置为空数组,关闭所有开启菜单。这个操作会清空选中项。
渲染项高度固定情况下,让Tree高度自适应
我们的目标是万一内容过多,Tree在占满了可占空间后,自己出现滚动条;在内容渲染后没有达到这个高度前,有多少内容Tree就显示多高。
这里关键要动态设置rowCount属性。
要设置这个属性,我们就不能同时设置Tree的height属性了。
我们监听updateComplete事件,这时更改的内容已经刷新,我们只需要通过rowCount属性告诉Tree:你要显示n行数据就好了。
接下来就是如何计算这个n了,这里采用了一个笨办法,渲染项的高度或者rowHeight 屬性是表示一行的高度,Tree允許的最大高度也是可以得到的,二者做個除法就好了,當然,要向下取整。
一个更完善的版本
上面的方法如遇到多于两级的数据,在孙子目录开启后,tree的尺寸就不对了。问题的原因是:这时tree正在显示多少项没法计算出来,进而无法准确设置rowCount属性。
更好的方法是不再监听updateComplete事件,改而监听itemOpen和itemClose事件,这两个事件在项被打开或者关闭的时候调度,在事件类型中,有当前操作的渲染项实例和操作的数据。有了当前操作的数据,我们可以计算出这次操作影响了多少项,然后我们再根据最多能显示多少项、一级数据的个数,决定rowCount合适的值。
以下是主要的代码:
private var showRow:uint;// tree 当前一共有多少项显示
private function findOpenNum(aimItem:Object,openItems:Array):uint
{
var numChildren:uint=aimItem.children.length;
for (var i:int = 0; i < aimItem.children.length; i++)
{
var it:Object=aimItem.children[i];
if(it.children)// 有子
{
if(openItems.indexOf(it)!=-1)// 子开
{
numChildren+=findOpenNum(it,openItems);
}
}
}
return numChildren;
}
protected function chapterTree_itemCloseOpenHandler(event:TreeEvent):void
{
var item:Object=event.item;
var tree:Tree=event.currentTarget as Tree;
var numChildren:uint=findOpenNum(item,tree.openItems as Array);
if(event.type==TreeEvent.ITEM_CLOSE)
{
this.showRow-=numChildren;
}else if(event.type==TreeEvent.ITEM_OPEN)
{
this.showRow+=numChildren;
}
if(this.showRow>=this.maxRow)
{
tree.rowCount=this.maxRow;
}else
{
tree.rowCount=this.showRow;
}
trace("变化项个数:"+numChildren+ ",显示个数:"+tree.rowCount);
}
itemOpen和itemClose事件共同的监听方法是chapterTree_itemCloseOpenHandler,这个方法中根据操作的数据获得这次操作在tree中添加或者减少了numChildren项数据,进而计算当前tree中有showRow项处于展示状态,接下来比较showRow和maxRow(显示的内容是否多于能显示的最大项数量),决定显示多少行数据。
其中的findOpenNum方法中,用到了递归,计算影响展开项的数量。这个数量包括当前子项和当前子项的展开项的的数量。
修改tree的dataProvider,需要设置showRow为一级数据的长度。