Apache – ‘Pre-measuring’ Flex Components

apache-flexflex3

I'm implementing a custom Flex component that provides a scrollable viewpoint onto a (possibly very large) data grid. I'm using the ItemRenderer pattern, such that I only have UIComponents for the elements visible on the screen at a given time. In other words, something similar to the standard DataGrid control.

One requirement I have is to dynamically size the grid cells to fit the provided data, such that the column widths and row heights are known up front. (The column widths and row heights can't fluctuate as the user scrolls and new cells come into view.)

This requirement implies a 'pre-measure' phase of the entire grid to be performed when the component's dataSource or itemRenderer is changed. I'd like to use the standard Flex component measuring operations to perform this pre-measurement phase.

My current strategy for this pre-measure phase is to:

  • Obtain an itemRenderer instance
  • Initialize the itemRenderer
  • For each cell in the data source:
    • Set the itemRenderer's 'data' object to that cell's data
    • 'commitProperties()' on the component
    • 'measure()' the component
    • Update column width/row height appropriately based on measurement results

I'd rather not attach the itemRenderer to the application's display list, but that means it won't be initialized by the framework. Also, I need the renderer's initialization and commitProperties/measurement phases to occur synchronously. I'm scared of how much of the Flex component lifecycle management framework I'll have to replicate to accomplish this.

So I call on those more experienced than I for words of wisdom:

  • Any thoughts on the feasibility of this strategy?
  • Any suggestions on how I could elegantly make use of the framework to perform this measurement for me?
  • Any better strategies to determine cell size?

Best Answer

I studied the framework code a bit, and if initial results are an indication, this isn't as painful as I feared. The guts of it:

var renderer:IListItemRenderer = getRenderer();
renderer.initialize();
for each (var cell:Object in cells) {
    renderer.data = cell;
    renderer.validateProperties();
    renderer.validateSize(true);
    // Access renderer's size properties here
}

Passing the 'recursive = true' flag to validateSize is the key that I was missing previously. Unfortunately there's no equivalent flag for validateProperties, so I'll probably have to implement that myself to make it reliable for arbitrary ItemRenderers.

Related Topic