Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Creative tools for business
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Flex Developer Center /

Understanding Flex itemRenderers – Part 2: External renderers

by Peter Ent

Peter Ent
  • Adobe

Content

  • An MXML itemRenderer
  • Determining an itemRenderer's width and height
  • Dynamically Changing the itemRenderer
  • An ActionScript itemRenderer
  • Reusable itemRenderers

Created

25 August 2008

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
Flex

Requirements

Prerequisite knowledge

To benefit most from this article, it is best if you are familiar with Flex Builder and ActionScript 3.0.

User level

Intermediate

Required products

  • Flex Builder 3 (Download trial)

In Part 1 of this series I showed you how to make an inline itemRenderer—that is, an itemRenderer whose MXML tags and ActionScript code are in the same file as the list using the itemRenderer. The code is inline with the rest of the code in the file.

You'll also recall that I said you should think of inline itemRenderers are being separate classes. The Flex compiler in fact extracts that inline code and makes a class for you. The benefit of inline itemRenderers is that the code is in the same place as the list, but that's also a drawback when the itemRenderer becomes complex. What I'm going to show you in this article is how to make the class yourself.

Extracting the itemRenderer into an external file has several benefits:

  • The itemRenderer can easily be used in multiple lists
  • The code is easier to maintain
  • You can use Flex Builder's Design View to sketch out the initial itemRenderer

This series includes the following articles:

  • Part 1: Inline renderers
  • Part 2: External renderers
  • Part 3: Communication
  • Part 4: States and transitions
  • Part 5: Efficiency

An MXML itemRenderer

In Part 1 you saw there was a complex itemRenderer used for a DataGrid:

<mx:DataGridColumn headerText="Title" dataField="title"> <mx:itemRenderer> <mx:Component> <mx:HBox paddingLeft="2"> <mx:Script> <![CDATA[ override public function set data( value:Object ) : void { super.data = value; var today:Number = (new Date()).time; var pubDate:Number = Date.parse(data.date); if( pubDate > today ) setStyle("backgroundColor",0xff99ff); else setStyle("backgroundColor",0xffffff); } ]]> </mx:Script> <mx:Image source="{data.image}" width="50" height="50" scaleContent="true" /> <mx:Text width="100%" text="{data.title}" /> </mx:HBox> </mx:Component> </mx:itemRenderer> </mx:DataGridColumn>

The itemRenderer is based on an HBox, contains an Image and a Text, and the background color is set according to the pubDate field of the item record. You can write this same itemRenderer as an external file using these steps:

  1. If you are using Flex Builder, create a new MXML Component file (I've named mine GridColumnSimpleRenderer, but use whatever you like) and set the root tag to be HBox. Don't worry about the size.
  2. If you are using the SDK alone, create a new MXML file (call it GridColumnSimpleRenderer.mxml) and set the root tag to be HBox.
  3. With the file open, copy everything between <mx:HBox> and </mx:HBox>, but do not copy those tags, since they are already in the file. The result should look something like this:
<?xml version="1.0" encoding="utf-8"?> <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300"> <mx:Script> <![CDATA[ override public function set data( value:Object ) : void { super.data = value; var today:Number = (new Date()).time; var pubDate:Number = Date.parse(data.date); if( pubDate > today ) setStyle("backgroundColor",0xff99ff); else setStyle("backgroundColor",0xffffff); } ]]> </mx:Script> <mx:Image source="{data.image}" width="50" height="50" scaleContent="true" /> <mx:Text width="100%" text="{data.title}" /> </mx:HBox>
  1. Save the file.

Now modify the DataGridColumn definition by removing the inline itemRenderer and replacing it with this:

<mx:DataGridColumn headerText="Title" dataField="title" itemRenderer="GridColumnSimpleRenderer">

Now run the application. You'll get a surprise. The surprise is how tall the rows are. That's because of the presence of height="300" on the itemRenderer.

Determining an itemRenderer's width and height

The List control always sets the itemRenderer's width. In this example, the explicit width="400" is ignored. You should write your itemRenderer to assume the width will change as the user changes the column or list's width.

The height is a different matter. If the list has an explicit rowHeight set, it will impose that height on each row, ignoring any height you've set on the itemRenderer. However, if you set the list's variableRowHeight property to true, then the list will seriously consider the itemRenderer's height. In this example, the height is explicitly set to 300, so each row is 300 pixels high.

To fix this, remove the explict height from the itemRenderer file and the application will work correctly.

Dynamically Changing the itemRenderer

In this example the set data() function has been overridden to examine the data and set the itemRenderer's backgroundColor. This is very common. Overriding set data() enables you to intercept the time when the data is being changed for a new row and you can you make style changes.

Common mistakes are:

  • Forgetting to call super.data = value;. This is VITAL—failure to do this will really mess up your itemRenderer.
  • Forgetting to reset the style(s) if any tests fail. It might be tempting to just set the color when the pubDate is in the future, but you have to remember that itemRenderers are recycled, and so the else statement is very necessary.

An ActionScript itemRenderer

Now you'll write another itemRenderer, this time using an ActionScript class. In the previous article there is a TileList with this inline itemRenderer:

<mx:itemRenderer> <mx:Component> <mx:HBox verticalAlign="top"> <mx:Image source="{data.image}" /> <mx:VBox height="115" verticalAlign="top" verticalGap="0"> <mx:Text text="{data.title}" fontWeight="bold" width="100%"/> <mx:Spacer height="20" /> <mx:Label text="{data.author}" /> <mx:Label text="Available {data.date}" /> <mx:Spacer height="100%" /> <mx:HBox width="100%" horizontalAlign="right"> <mx:Button label="Buy" fillColors="[0x99ff99,0x99ff99]"> <mx:click> <![CDATA[ var e:BuyBookEvent = new BuyBookEvent(); e.bookData = data; dispatchEvent(e); ]]> </mx:click> </mx:Button> </mx:HBox> </mx:VBox> </mx:HBox> </mx:Component> </mx:itemRenderer>

You'll make that into an ActionScript external itemRenderer. You'll need to follow these steps:

  1. Create a new ActionScript class. Call it BookTileRenderer.as and make it extend HBox, just like the inline itemRenderer.
package { import flash.events.MouseEvent; import mx.containers.HBox; import mx.containers.VBox; import mx.controls.Button; import mx.controls.Image; import mx.controls.Label; import mx.controls.Spacer; import mx.controls.Text; public class BookTileRenderer extends HBox { public function BookTileRenderer() { super(); } } }
  1. Create member variables to hold the references to the child components.
private var coverImage:Image; private var titleText:Text; private var spacer1:Spacer; private var authorLabel:Label; private var pubdateLabel:Label; private var spacer2:Spacer; private var buyButton:Button;
  1. Override the createChildren() function to create the child components and add them to the HBox.
override protected function createChildren():void { coverImage = new Image(); addChild(coverImage); var innerBox:VBox = new VBox(); innerBox.explicitHeight = 115; innerBox.percentWidth = 100; innerBox.setStyle("verticalAlign","top"); innerBox.setStyle("verticalGap", 0); addChild(innerBox); titleText = new Text(); titleText.setStyle("fontWeight","bold"); titleText.percentWidth = 100; innerBox.addChild(titleText); spacer1 = new Spacer(); spacer1.explicitHeight = 20; innerBox.addChild(spacer1); authorLabel = new Label(); innerBox.addChild(authorLabel); pubdateLabel = new Label(); innerBox.addChild(pubdateLabel); spacer2 = new Spacer(); spacer2.percentHeight = 100; innerBox.addChild(spacer2); var buttonBox:HBox = new HBox(); buttonBox.percentWidth = 100; buttonBox.setStyle("horizontalAlign","right"); innerBox.addChild(buttonBox); buyButton = new Button(); buyButton.label = "Buy"; buyButton.setStyle("fillColors",[0x99ff99,0x99ff99]); buyButton.addEventListener(MouseEvent.CLICK, handleBuyClick); buttonBox.addChild(buyButton); }

I've indented the code to show the parent-child relationships. Also, make sure you include an event listener on the Buy button.

  1. Override the commitProperties() function and set the user interface controls from the data.
override protected function commitProperties():void { super.commitProperties(); coverImage.source = data.image; titleText.text = data.title; authorLabel.text = data.author; pubdateLabel.text = data.date; }
  1. Add the click event handler for the Buy button.
private function handleBuyClick( event:MouseEvent ) : void { var e:BuyBookEvent = new BuyBookEvent(); e.bookData = data; dispatchEvent(e); }
  1. Modify the TileList in the main application to use the itemRenderer ActionScript class. Simply remove the inlineItemRenderer and replace it with an itemRenderer property right in the tag.
<mx:TileList id="mylist" x="29" y="542" width="694" itemRenderer="BookTileRenderer" dataProvider="{testData.book}" height="232" columnWidth="275" rowHeight="135" >

If you are going to use an existing container class, such as HBox, I wouldn't bother doing this in ActionScript. You can see it is more complex than using an MXML file and, quite frankly, there is little performance benefit to it.

Reusable itemRenderers

Here's an example of an itemRenderer that displays a numeric value using the CurrencyFormatter. I call it PriceFormatter:

<?xml version="1.0" encoding="utf-8"?> <mx:Text xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script> <![CDATA[ import mx.controls.dataGridClasses.DataGridListData; [Bindable] private var formattedValue:String; override public function set data(value:Object):void { super.data = value; formattedValue = cfmt.format( Number(data[(listData as DataGridListData).dataField]) ); } ]]> </mx:Script> <mx:CurrencyFormatter precision="2" id="cfmt" /> <mx:text>{formattedValue}</mx:text> </mx:Text>

The key to this itemRenderer is shown in red, setting the bindable variable formattedValue. First, you'll see that <mx:CurrentFormatter> was defined as an MXML tag (you can do this in ActionScript, too, if you prefer) with an id of cfmt. In the example above, the formattedValue is set to the result of calling the CurrentFormatter's format() function.

The function takes a Number as its parameter type, so the value is cast to Number—that's because the dataProvider for the list is XML, and everything in XML is text; if you use a Object for your data and you have real numeric values, doing the Number cast will be harmless.

As you know, data is the property that holds the item being displayed by the itemRenderer. Using [ ] notation is another way of accessing the fields of the data item. For example, data['price'] would be the price column. But to make this itemRenderer resuable, you cannot code for a specific field, so a more generic way is needed.

That's where listData comes in. All Flex components which implement the IDropInListItemRenderer interface have a listData property.

Note: Most controls, such as Text, Label, Button, CheckBox, and so forth, implement IDropInListItemRenderer. Most containers, such as HBox, Canvas, etc. do not implement that interface. If you want to use listData in an itemRenderer that extends a Container, you will have to implement IDropInListItemRenderer yourself; I'll cover that in the next article.

The listData given to an itemRenderer contains, among other things, the rowIndex and the control that owns the itemRenderer—the DataGrid, List, or TileList. When you have an itemRenderer being used for the DataGrid, the listData is actually a DataGridListData object—which includes the columnIndex and the dataField associated with the DataGridColumn. Here's the breakdown of the statement above, starting from the inside:

  • listData as DataGridListData—This casts the listData to a DataGridListData object so you have access to its dataField
  • .dataField—the field for the column being rendered. This is what makes this itemRenderer generic. You can use this itemRenderer for multiple columns. In this example the dataField is 'price'.
  • data[ ... ]—This accesses the data for the specific field in the item. In this example it will be the price column.
  • Number( ... )—This casts the value to a Number because the format() function requires a Number parameter.
  • cfmt.format( ... )—This formats the value as a currency.

Where to go from here

Use whatever makes you comfortable when implementing itemRenderers. Some people only work in ActionScript, which is great when you've got experience with Flex and ActionScript. MXML makes quick work of simple itemRenderers, too.

In Part 3 (coming soon) I'll discuss more communication between itemRenderers and the rest of the application.

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License

 

Tutorials & Samples

Tutorials

  • Flex mobile performance checklist
  • Flex and Maven with Flexmojos – Part 3: Journeyman
  • Migrating Flex 3 applications to Flex 4.5 – Part 4

Samples

  • Twitter Trends
  • Flex 4.5 reference applications
  • Mobile Trader Flex app on Android Market

Flex User Forum

More
07/25/2011 Flash Player Debug Issues - Safari 5.1 & Chrome 13
04/22/2012 Loader png - wrong color values in BitmapData
04/22/2012 HTTPService and crossdomain.xml doesn't work as expected
04/23/2012 Memory related crashes in Flex application

Flex Cookbook

More
04/06/2012 How to detect screen resize with a SkinnableComponent
02/29/2012 Embed Stage3D content inside Flex application components
02/15/2012 Custom WorkFlow Component
02/09/2012 Using Camera with a MediaContainer instead of VideoDisplay

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement