[Flex]flex3:利用itemRenderer创建在线书店的图书信息显示页面

第一部分:预备知识—-认识itemRenderer

我们经常用itemRenderer,使用List,DataGrid,TileList等组件时经常动不动就来个itemRenderder。虽然很熟悉了,但是我打算今天还是再好好认识一下它。
使用itemRenderer有两点需要注意:
1,对于flex框架,使用itemRenderer很件很耗费内存的事,如果可以避免尽量不要用。
2,一个误会
假设我有一个List组件,与他绑定的数据有1000条,现在我要渲染这个List。是不是要创建1000个itemRenderer实例啊?这是个误会。
再假设,我这个List只能显示10个条目,那么或许flex或许只会给你创建12个itemRender实例,至于为什么多出两个,是出于缓 存和表现的原因。你拖动滚动条,第一条和第二条项目消失了,但是它们对应的itemRenderder只是改变了位置,加载了新的数据,还显示第十一和十 二条项目。所以,itemRenderer是重用(recycled)的,这一点得格外注意。不要试图调用第X条的itemRenderer再修改它,因 为如果此时它不再显示范围内,第X条对应的itemRenderer就不知道用来显示谁去了?要想改变一个itemRenderer,最好的办法就是根据 它的数据来改变它。
第二部分:初级—-inline itemRenderers
什么叫inline itemRenderer?这就是跟调用它的组件(以后成为list control)写在一起的那种。这是比较简单的那种。现在我们就用这种的itemRenderer先写个显示书单图书信息的页面。
下面是代码:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    
<mx:Script>
        
<![CDATA[
            [Bindable]
    public var bookInfo:XML=
            <books
>
                
<book>
                    
<name>手到病自除</name>
                    
<price>20.10</price>
                    
<writer>杨奕</writer>
                    
<image>bookpic/sdbzc.jpg</image>
                    
<instore>yes</instore>
                
</book>
                
<book>
                    
<name>好妈妈胜过好老师</name>
                    
<price>17.30</price>
                    
<writer>尹建莉</writer>
                    
<image>bookpic/hmmsghls.jpg</image>
                    
<instore>yes</instore>
                
</book>
                
<book>
                    
<name>货币战争</name>
                    
<price>26.90</price>
                    
<writer>宋鸿兵</writer>
                    
<image>bookpic/hbzz.jpg</image>
                    
<instore>no</instore>
                
</book>
                
<book>
                    
<name>不抱怨的世界</name>
                    
<price>15.4</price>
                    
<writer>鲍温</writer>
                    
<image>bookpic/bbydsj.jpg</image>
                    
<instore>yes</instore>
                
</book>
                
<book>
                    
<name>历史是个什么玩意儿</name>
                    
<price>19.60</price>
                    
<writer>袁腾飞</writer>
                    
<image>bookpic/lsssmwy.jpg</image>
                    
<instore>yes</instore>
                
</book>
                
<book>
                    
<name>不生病的智慧</name>
                    
<price>17.20</price>
                    
<writer>马悦凌</writer>
                    
<image>bookpic/bsbdzh.jpg</image>
                    
<instore>no</instore>
                
</book>
            
</books>
        ]]>
    
</mx:Script>
    
<mx:TileList dataProvider="{bookInfo.book}" width="600" height="600" variableRowHeight="true" x="100" y="0">
        
<mx:itemRenderer>
            
<mx:Component>
            
<mx:VBox width="150" height="200" horizontalAlign="center">
                
<mx:Image source="{data.image}"/>
                
<mx:Label text="{data.name}"/>
                
<mx:Button label="buy"/>
            
</mx:VBox>    
            
</mx:Component>
        
</mx:itemRenderer>
    
</mx:TileList>
</mx:Application
要使用inline itemRenderer,方法就是在<mx:itemRenderer>标签里嵌套一个<mx:component>的标签。 在<mx:component>就是你要用来渲染数据的组件。要记住的一点就是应该把<mx:component>里的代码看做 一个单独的外部定义的类,它与其他的代码的并不是一起的。所以,我们不能直接调用写在<mx:Script>里的函数。当我们要处理buy那 个按钮时,就会遇到这个问题。这个按钮虽然简单,但是它负责着itemRender与外部的交互。现在,先不考虑这些,我们只考虑如何调用外部的函数。假 设,在上面的<mx:Script>里有一个buyBook()函数,在上面的itemRender里必须如此调用:
<mx:Button label="buy" click="outerDocument.buyBook()"/>
重点就是那个outerDocument。特别注意一点,buyBook()函数必须声明为public。
好,到现在为止,我们做出的东西就如下面那个样子。
看来背景色不应该用白色的,待会在改吧!O(∩_∩)O~
第三部分:中级—–引用外部组件作为itemRenderer
其实,可以写基于任何组件的自定义组件作为itemRender,但是具体来讲还是有区别的。在选基类时考虑两方面:一就是性能,很明显 Canvas比HBox更轻量级,当然最好是用基于UIComponent的组件作为itenRenderer,这个稍后会写;二就是,看组件是否实现了 IDropInListItemRenderer接口,至于这个接口的作用,稍后会遇到。
现在我们现做的,就是把上面嵌入list control的itemRenderer部分移到外面的文件,我们建立一个BookInfoRenderer组件好了,基于HBox的。
itemRenderer的代码:
Code
引用itemRenderer的相关代码:
<mx:TileList columnWidth="200" rowHeight="150" itemRenderer="BookInfoRenderer" dataProvider="{bookInfo.book}">    
</mx:TileList>
通常情况下,itemRenderer的宽度不会被考虑,即使你设定了。如果你设定了rowHeight,那么原来的itemRenderer的高度就会被忽略,如果你不想让他被忽略,设定variableRowHeight为true。
引用外部的类作为itemRenderer就是这个样子。
现在我们研究一下如何动态的改变itemRenderer。前面说过要改变itemRenderer就必须根据它的数据,因为它是recycled。
重新写一下itemRenderer组件,重写后,书的价格被格式化了(加了个$)。
Code
重写set data方法时,千万不要忘记super.data=value这句话。
现在是这个样子:
第四部分:高级——与list control的交互
那个像是TileList,List,DataGrid之类的就叫list control,反正技术文档里就是这么说的,不知道该怎么翻译,就这样叫吧。那个itemRenderer好像叫做渲染器,inlineh好像翻译为行内。不知道怎么翻译准确,就用原名吧。
现在在来研究那个buy按钮。点了它之后,应该弹出一个对话框告诉用户买的什么东西,价格是多少。现在的问题是,这个弹出对话框的函数写在哪 里,写在itemRenderer对应的函数里吗?按理说,没什么错误。但是我们应该谨记这样的原则,itemRenderer是用来表现数据的,而非处 理数据,处理数据是list control的任务。那好,弹出对话框的函数应该写在list control对应的文件里。那么又遇到了一个问题,弹出的内容包含着书的信息,这个信息保存在itemRenderer的数据里,如何把这个数据传给 list control呢?或许,最好的方法就是利用Event,当点击按钮时派发一个自定义事件,事件里包含着书的信息。好的,现在剩下的最后一个问题就是这个 事件由谁来派发?itemRenderer? or list control?按理说,谁派发都一样,反正事件会冒泡,即使用itemRenderer来派发,list control也会捕捉到。但是,为了逻辑上更清楚和使用上更方便,我们让list control来派发事件。逻辑上更清楚似乎有点不好理解,但是记住itemRenderer的任务是表现数据。使用上更方便时显而易见的,而且可移植性 还会好些,待会就会看到。当然,让itemRenderer来派发事件,也不会有什么错误,而且更方便一些。
好的,现在先定义一个事件:BuyBookEvent
Code
定义完了事件,我们在自定一个TileList组件。这就是有点麻烦的地方,因为它要派发事件,所以必须自定义一下。好在,还不是太麻烦。
MyTileList:
Code
好了,现在我们将迎来最复杂的一步,调整itemRenderer。其实复杂的原因很简单:继承自HBox的itemRenderer不能够调 用到他的list control。前面讲过,你要用那个组件作为基类来实现itemRenderer是有区别的,区别之一就是看它有没有实现 IDropInListItemRenderer接口。只有实现这个接口的组件作为itemRenderer才能有方法调用到他的ilst control。Button,CheckBox,Label都实现了,但是Hbox没有实现。没有实现,我们就必须自己实现它。
来吧!
我把代码再全写一遍:
Code
虽然,涉及到的知识有些复杂但是步骤还是很简单的:
第一步:在跟标签写入implements="mx.controls.listClasses.IDropInListItemRenderer"
第二步:导入import mx.controls.listClasses.BaseListData;
第三步:把相关的代码拷入。
好了,现在的问题是,listData是做什么用的?因为我们实现IDropInListItemRenderer接口就是为了实现这个属性。它是做什么,有些复杂,可以去看参考资料,这里就不粘贴了。只说说怎么用它好了。
回到itemRenderer文件:处理buy按钮的事件:
<mx:Button label="buy">
        
<mx:click>
            
<![CDATA[
                (listData.owner as MyTileList).disPatchBookEvent(data);
            ]]
>
        
</mx:click>
        
</mx:Button>
现在回到list control所在的文件,捕获事件:
<local:MyTileList columnWidth="200" rowHeight="150" buyBook="doBuy(event)"
        itemRenderer
="BookInfoRenderer" dataProvider="{bookInfo.book}"/>
看到了吗?方便的地方就是我可以在标签里直接buyBook="doBuy(event)"这样写。
再加上处理函数doBuy(evnt)就大功告成了.
private function doBuy(event:BuyBookEvent):void{
                mx.controls.Alert.show(event.bookData.name+":"+event.bookData.price);
            }
好了就先写到这里吧,已经写了这么多了,O(∩_∩)O~。
例子虽然简单,可是内容还是很多的……
至于继承自UIComponent的itemRenderer,大概也是这个思路,有空再说吧!
赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏