I need to set the text of a spark label and then position suc开发者_运维技巧h label along the x axis depending on its width. Unfortunately, it seems that the width of the label does not update right away and thus the positioning will fail. I can listen to updateComplete events on the label and update its position then, but that means repositioning the label a lot more often than I would like (updateComplete fires off a lot more often than upon changing width). Any ideas on how to properly handle what would appear to be a trivial task?
Here's a code snippet that shows what I described above. If you press the button you will see 3 traces: the label width before changing its text, right after setting its text, and when the label is done updating itself. Would love to know if there's a way to get the correct width without having to listen to updateComplete events... The button and the VGroups are just there to run the example
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function button1_clickHandler(event:MouseEvent):void
{
trace("label width = ", lb.width);
lb.addEventListener(FlexEvent.UPDATE_COMPLETE, lb_updateCompleteHandler);
lb.text = "hello world!";
trace("label width post change= ", lb.width);
}
protected function lb_updateCompleteHandler(event:FlexEvent):void
{
lb.removeEventListener(FlexEvent.UPDATE_COMPLETE, lb_updateCompleteHandler);
trace("label width post update complete = ", lb.width);
}
]]>
</fx:Script>
<s:VGroup>
<s:Button label="go" click="button1_clickHandler(event)"/>
<s:Label id="lb" text="h" x="10" y="10" />
</s:VGroup>
</s:Application>
The following worked for me. Simple yet works.
var l:Label = new Label();
l.text = "That'll do";
var tlm:TextLineMetrics = l.measureText( l.text);
Alert.show( tlm.width + " is what you are looking for");
VGroup
is a Group
with VerticalLayout
. It doesn't allow to have custom positioning inside group (with x
and y
). To have this possibility use Group
with (default) BasicLayout
.
If you use a callLater(), you can "capture" variables in the current scope, but also have it execute after the change in the width
has been propagated. For example:
callLater(function():void
{
trace("label width in callLater = ", lb.width);
});
UPDATE: I think I should elaborate a little more to make clear what I meant by "capturing" values. This can be done with the following simple illustration:
callLater(function(prevWidth:Number):void
{
trace("previous label width in callLater = ", prevWidth); // 8
trace("label width in callLater = ", lb.width); // 64
}, [lb.width]);
As the example demonstrates, the parameters that you pass in through the args
Array (, i.e., the [lb.width]
which becomes prevWidth
) take the current value (ie., they pass by value), whereas, the variables you make direct reference to in the function are actually in the scope when the function gets executed (ie., a closure).
You could do this with the event listener also, but with the callLater() it's a little simpler.
looks like listening to resize events does the trick and is not quite as general as updateComplete events, so I'm calling that the "correct answer". There may be a better way to do this when you're trying to position stuff by hand due to performance optimization, although I'm not sure what it is yet.
You can call lb.validateNow() after setting text, this way you will get new width right away. But suggest you to read about components lifecycle not to have such trivial questions.
And yes, as people pointed out already, no repositioning will work with such layout.
精彩评论