Tuesday, April 14, 2009

More ItemRenderer Woes

Update: Ok, I am officially frustrated. It seemed like adding the validateNow() was working, but as I ran through more test cases, it definitely wasn't. The final solution that seems to work consistently is to NOT use a percentWidth on the Text component. You can bind the width of the Text component to the parent's width, and you get the benefit of setting an explicitWidth on the Text component which fixes the incorrect sizing problems and it fits properly in the parent container.

I have been struggling recently with getting a custom ItemRenderer in a List to display correctly. It basically consists of a small Image component used as an icon, a Text field used for a title to the right of the icon, and a Text field used as a description below the title. I arranged these on a Canvas and sized them using percent widths. When I scrolled the list, the sizes of the renderers would vary dramatically, sometimes only displaying the title, sometimes displaying with too much whitespace. I found what seems to be a solution on Kalen Gibbons blog. Basically, you need to get the Text fields validated before the size of the renderer is calculated. So, for each Text component, I am calling validateNow() on it in my commitProperties() method. This is a little different than Kalen's solution. When I called validateNow() on the renderer and not on the Text components, it did not fix the problem.

As an aside, in my attempts at fixing this issue, I re-implemented the renderer by extending mx.controls.listClasses.ListItemRenderer. When I did this, the Text components didn't display at all. The reason for this isn't totally clear, but I did discover part of the cause. The Text component, when you either set left/right constraints or a percentWidth (and don't set a height) the Text component does a special two pass calculation of the height. On the first pass the component will bypass measure() and wait until updateDisplayList() is called to get it's unscaledWidth. It then calls invalidateSize() which causes measure() to get called again and then uses the width obtained from updateDisplayList to calculate the height of the component. The problem is that when you add a Text component to the ListItemRenderer and specify the percent width, the updateDisplayList() for the Text component always gets called with a width = 0. I don't know why this is happening, but because of this it causes the 2 pass calculation to fail. So basically, don't use a Text component in ListItemRenderer or you will need to set it's size explicitly.