Recently, I was working on a project in which the location of one object on the stage was based on the size of another object but the size of the latter object was not known until run-time. At first glance, this might sound like an easy problem to solve. Just add a few lines of code to your appComplete or creationComplete handler and adjust the location of the former component based on the size of the latter, right? Unfortunately, it’s not so simple, as the following example shows:
protected function application1_applicationCompleteHandler(event:FlexEvent):void { var alphabet:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; text1.text = alphabet.substr(0, Math.random() * 26); text2.x = text1.x + text1.width + 10; } <s:RichText id="text1" /> <s:RichText id="text2" text="This is positioned after the alphabet text field" /> |
If you run this code in an app with no layout what you’ll see are the two text fields, one on top of the other. The first time I tried this I was surprised as I expected text1.width to contain the width, in pixels, of the RichText object now that it had been assigned some characters. But, in fact, the width property is 0 at this time. I tried several variations of the app above, including using measuredWidth and various of the other width properties, all to no avail.
After grappling with this problem for an hour it became clear that I was missing some key principle(s) of Flex development. I had a pretty good idea that it was related to the Flex component life cycle but didn’t know specifically how.
Last month after a Flex session at the Adobe MAX conference I asked the presenter where I could learn more about the Flex component life cycle. He referred me to a detailed paper called Understanding the Flex 3 Component Lifecycle by James Polanco, formerly of Adobe. At 36 pages this paper contains a wealth of information on what happens when components are instantiated and added to the stage in a Flex app. And although it was very enlightening I found, after studying it, that I still didn’t have a good handle on exactly what I needed to do. It all felt a bit theoretical and, in fact, when I went back to the code I wasn’t sure which Flex SDK methods I should override and in what order.
So, I did some experimenting and eventually, I came up with the code I needed. Here is a sample app which illustrates some of the essential concepts and shows how to position a text field immediately to the right of another dynamically sized text field. Here’s the app, functioning correctly (note that the number of characters taken from the alphabet string will change each time you load this page):
Right-click to View Source or download the .fxp. And here’s the code:
protected function application1_applicationCompleteHandler(event:FlexEvent):void { var alphabet:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; text1.text = alphabet.substr(0, Math.random() * 26); invalidateDisplayList(); trace("appComplete"); } override protected function commitProperties():void { trace("commitProperties; text1.text: " + text1.text + "; text1.measuredWidth: " + text1.measuredWidth); } override protected function measure():void { trace("measure; text1.text: " + text1.text + "; text1.measuredWidth: " + text1.measuredWidth); } override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { trace("updateDisplayList; text1.text: " + text1.text + "; text1.measuredWidth: " + text1.measuredWidth); if(text1.text.length > 0) { text2.x = text1.x + text1.measuredWidth + 10; } } <s:RichText id="text1" /> <s:RichText id="text2" text="This is positioned after the alphabet text field" /> |
I won’t go into the details of the various phases of the Flex component life cycle as that has been well covered in James Polanco’s paper and other resources (see links at the end of this post). I’ll just point out a few of the specifics of this app. First, when you run it, you’ll see the following trace output:
commitProperties; text1.text: ; text1.measuredWidth: 0 measure; text1.text: ; text1.measuredWidth: 0 updateDisplayList; text1.text: ; text1.measuredWidth: 0 appComplete updateDisplayList; text1.text: ABCDEFG; text1.measuredWidth: 57 measure; text1.text: ABCDEFG; text1.measuredWidth: 57 updateDisplayList; text1.text: ABCDEFG; text1.measuredWidth: 57 |
Note that the first time the methods are called text1 doesn’t actually contain any text so there’s no way to correctly set the position of text2 within those handlers. And inside the appComplete handler it’s too late. As pointed out above, immediately after the text1.text assignment statement the width of text1 is 0. This is because of the order in which the Flex SDK calculates the sizes and positions of display objects.
The key to making things work is to call invalidateDisplayList after the text1.text assignment statement. This tells Flex to run through its measurement and layout calculations again. Then, when updateDisplayList is called the second time that’s the time we can get the width of text1 and calculate the position of text2.
Flex Component Lifecycle Resources
RJ Owen’s slides on the Flex 4 Component Lifecycle
James Polanco’s and Aaron Pedersen’s Flex 4 Lifecycle Best Practices


{ 5 comments… read them below or add one }
I believe your original code would have worked with the following:
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
var alphabet:String = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
text1.text = alphabet.substr(0, Math.random() * 26);
text1.validateNow();
text2.x = text1.x + text1.width + 10;
}
Thomas,
I gave your code a try just now but it didn’t work for me. (text2 overwrites text1.)
David Salahi
You are correct. Here is the fix to make it work:
text2.x = text1.x + text1.measuredWidth + 10;
With a programmatic approach (like above), we need to use ::measuredWidth. If we are using MXML declarative approach then this will work:
With a programmatic approach (like above), we need to use ::measuredWidth. If we are using MXML declarative approach then this will work:
<s:Label id=”text1″ x=”50″ y=”20″ />
<s:Label id=”text2″ y=”20″ x=”{text1.x + text1.width + 10}” text=”Databinding to offset”/>
Thomas,
You’re right about the second approach (setting the x position in the MXML code). This highlights an advantage of using MXML over ActionScript: doing things in MXML avoids the necessity of manually handling the component life cycle. With MXML the compiler takes care of that for you.
Although I preferred using ActionScript to MXML, where possible, when first starting to program in Flex I’ve learned instead to prefer using MXML. Things just work more smoothly.
Regards,
David Salahi
{ 1 trackback }