I have written two posts (here and here) on creating variable size item renderers for List based components that size correctly. The example for the TreeItemRenderer mostly works, but still has some issues that have been plaguing me for a while. I decided to spend some time trying to figure out what the problem really is and made significant progress that I wanted to share.
TreeRenderer Example Version 2
I have made some changes to the original TreeRendererExample that significantly improve its behavior. The example code is hosted on the Flexnaut googlecode site under the TreeRendererExample2 project.
Enhancement 1
The original custom renderer was a lot more complicated than it needed to be. I was adding a resize event listener to the tree (for each renderer) that set the Text component's width/height to NaN. The measure() override looked like this:
override protected function measure():void
{
super.measure();
description.width = explicitWidth - super.label.x;
measuredHeight += description.measuredHeight;
}Then in updateDisplayList I would set the height of the Text component to it's measuredHeight. In the new version, I don't set any resize listener on the Tree component and I don't do set any properties on the Text component. I just use the Text component's size to calculate the size of the renderer:
override protected function measure():void
{
super.measure();
measuredHeight = measuredMinHeight = measuredHeight description.getExplicitOrMeasuredHeight();
}Then, in updateDisplayList, I do the following to size the Text component:
//This forces the Text component to calculate it's height description.width = width - description.x; //This sets the Text component to the calculated width & height description.setActualSize( description.getExplicitOrMeasuredWidth(), description.getExplicitOrMeasuredHeight() );
With these changes, everything almost works correctly. The item renderers all size correctly, but the problem is that the renderers seem to overlap each other now. This condition can be detected in the renderer updateDisplayList by comparing the unscaledHeight parameter to the measuredHeight parameter. It looks like there is a bug in ListBase which causes it to not detect changes in the height of the renderers. Fortunately, the fix is simply to add this line to updateDisplayList:
if ( unscaledHeight != measuredHeight ) callLater( ListBase(owner).invalidateList );
This causes the protected property itemsSizeChanged on ListBase to be set to true, and invalidates the display list. The callLater is necessary, because updateDisplayList can't be called while the current updateDisplayList is running.
With these changes, we now have a much simpler and functional TreeItemRenderer with a Text component. The following demonstrates the improved behavior:
Unable to initialize flash content
Original Broken Version - Scroll and click around to see broken behavior
Unable to initialize flash content
New Version - Scroll and click works as expected
Check out the source!