When you create dinamically a display object in ActionScript the registration point is at the top right (obviously it depends also on the way you design the object into the library) and expecially in Flex it can represent an issue when you want to align an object to a point considering the center of this object.
In order to avoid this issue it's enough to calculate the dispalcement between the center of the object and the actual X and Y coordinates, the following script is the function you have to use to calculate the diaplacement, attached there is a .fla file that show you a complete sample (please register in order to download the file).
function displacement(target:DisplayObjectContainer, x:Number, y:Number):Point{
var bounds:Rectangle = target.getBounds(this);
var centerX:Number = bounds.x + (bounds.width / 2);
var centerY:Number = bounds.y + (bounds.height / 2);
var deltaX:Number = target.x - centerX;
var deltaY:Number = target.y - centerY;
var point:Point = new Point();
point.x = x + deltaX;
point.y = y + deltaY;
return point;
}
When reading a byte array in ActionScript (like in C) the null value is read as a string termination. When you try use the
readUTFBytes method over a ByteArray if the data contain a null value (0x00) the ActionScript interpreter stop the reading and retunr you a truncated string, in order to avoid this issue you can simply parse the data before using the method readUTFBytes. Following a small sample where the variable bytedata represents the raw data recovered from your read operation.
var ba:ByteArray = new ByteArray();
for(var i:int = 0; i < bytedata.length; i++){
if(bytedata[i] != 0x00){
ba.writeByte(bytedata[i])
}else{
ba.writeByte(0x0A)
}
}
ba.position = 0;
var data:String = ba.readUTFBytes( ba.length );
Binary search is a way of searching data inside a sorted list that can drastically reduce the time of the search operations.
In this example I'm searching for an integer because it's the most reliable data type in as. When comparing strings or complex objects some expedient should be taken to be sure that the comparison it's correct. The Comparable interface of Java could be a good solution.
To give insight about how fast is this method, to run 500 searchs in a list of 1000000 items the binarySearch took 2 to 5 milliseconds doing only 16-17 comparisons.
The regular indexOf method of the Array class took 450 milliseconds to perform the same task.
The bit operations (>>>) used to take the middle number (probe) also helped a bit, using a regular division (/2) increased the time to run the task to 4-9 milliseconds.
public function binarySearch(keys:Array, target:int):int
{
var high:int = keys.length;
var low:int = -1;
while (high - low > 1)
{
var probe:int = (low + high) >>> 1;
if (keys[probe] > target)
{
high = probe;
}
else
{
low = probe;
}
}
return (low == -1 || keys[low] !== target) ? -1 : low;
}
A fast way to replace
tokens in strings is to use the method
replace of the
mx.utils.StringUtil class.
The method will search for tokens with the pattern {n} and replace them with the parameters you give.
This is most effective when you have the string in your resource bundle and you need to inject some data into it.
var itemName:String = "Book";
var itemPrice:int = 10;
var localized:String = resourceManager.​getString("IB_store", "store.confirm");
trace(localized); // "You bought {0} for {1} €"
var message:String = StringUtil.substitute(localized, itemName, itemPrice);
trace(message); // "You bought Book for 10 €"
Regular Expressions are very powerful but sometime not so easy to use, recently we have had the need to get a deserialize an object that cames from a database and that contains in each node the name of the property, its value and its datatype.
The raw binary data that we got are expressed with the following syntax
<property name="crop" value="" type="com.gnstudio.rikorda.core.model.canvas.vo::Crop" >
<property name="points" value="" type="__AS3__.vec::Vector.<flash.geom::Point>" >
<property type="__AS3__.vec::Vector.<flash.geom::Point>" >
<property name="point" value = "" type = "flash.geom::Point">
<property name="x" value="" type="Number" />
<property name="y" value="" type="Number" /></property></property> In the Flash Platform when you try to read this UTF bytes and cast them to an XML object you get an exception because there is the
< and the
> chars in the attribute, in order to solve this issue we used a regular expression to get the value stored in the attribute. The regular expression uses a named group to access this data into the exec method and inside this method there is the logic to replace the
< and
> chars with the right HTML entities.
Some useful links:
http://gnosis.cx/publish/programming/regular_expressions.html http://www.radsoftware.com.au/articles/regexlearnsyntax.aspx http://www.radsoftware.com.au/regexdesigner/ http://help.adobe.com/en_US/ActionScript/3.0_...3e3d118a9b90204-7e9a.html http://livedocs.adobe.com/flex/3/html/help.ht...gular_Expressions_09.html http://www.regular-expressions.info/examples.html http://www.regular-expressions.info/brackets.html http://wiki.tcl.tk/989
var content:String = '<property name="crop" value="" type="com.gnstudio.rikorda.core.model.canvas.vo::Crop" >' +
'<property name="points" value="" type="__AS3__.vec::Vector.<flash.geom::Point>" >' +
'<property type="__AS3__.vec::Vector.<flash.geom::Point>" >' +
'<property type="__AS3__.vec::Vector.<flash.geom::Point>" >' +
'<property name="point" value = "" type = "flash.geom::Point">' +
'<property name="x" value="" type="Number" />' +
'<property name="y" value="" type="Number" />' +
'</property>' +
'</property>';
trace("CONTENT BEFORE:", content, "\n");
var ltExp:RegExp = new RegExp("\\<", "g");
var gtExp:RegExp = new RegExp("\\>", "g");
var attributeName:String = "type";
var groupName:String = "attribute";
var attributes:RegExp = new RegExp("<(?:[^>\"']|\"[^\"]*\"|'[^']*')+?\\s" + attributeName + "\\s*=\\s*(?P<" + groupName + ">\"[^\"]*\"|'[^']*')(?:[^>\"']|\"[^\"]*\"|'[^']*')*>", "g");
var err:Error;
do {
try{
var data:String = attributes.exec(content)[groupName];
var clone:String = data;
var toReplace:Boolean;
if(clone.search(gtExp) > -1){
clone = clone.replace(gtExp, ">");
toReplace = true;
}
if(clone.search(ltExp) > -1){
clone = clone.replace(ltExp, "<");
toReplace = true;
}
if(toReplace){
var reg:RegExp = new RegExp("\\" + data, "g");
content = content.replace(reg, clone);
}
}catch(error:Error){
err = error
break;
}
} while ( !err);
trace("CONTENT AFTER:", content);
If you want to detect how many paragarphs are contained into an XML flow you can simpy use the power of E4X and the default namespace directive of ActionScript 3.0.
var data:XML = <TextFlow cffHinting="horizontalStem" color="#000000" columnCount="inherit" columnGap="inherit" columnWidth="inherit"
fontFamily="Verdana" fontLookup="embeddedCFF" fontSize="26" lineBreak="inherit" paddingBottom="15" paddingLeft="15"
paddingRight="15" paddingTop="15" renderingMode="cff" verticalAlign="inherit"
whiteSpaceCollapse="preserve" xmlns="http://ns.adobe.com/textLayout/2008">
<p>
<span>
Enter your text here...
</span>
</p>
<p>
<span>
Enter your text here...
</span>
</p>
</TextFlow>;
var textFlowNamespace:Namespace = new Namespace("http://ns.adobe.com/textLayout/2008");
default xml namespace = textFlowNamespace;
trace(data.p.length())
To use embedded fonts with Adobe Text Layout Framework (TLF) you need to switch on the 'embedAsCFF' option and use Flex SDK 4.0 to compile the fonts. Please note that the 'embedAsCFF' attribute replaced the old 'cff' attribute in Flex SDK 4.0. After succesfully embedding the fonts make sure that you set the fontLookup property of the TextFLow to FontLookup.EMBEDDED_CFF.
// Embedding 'Anonymous Pro' font family
[Embed(source='/fonts/Anonymous Pro B.ttf', embedAsCFF='true', fontName='AnonymousPro', fontWeight='bold', fontStyle='normal', mimeType='application/x-font')]
private static var AnonymousProB:Class;
[Embed(source='/fonts/Anonymous Pro BI.ttf', embedAsCFF='true', fontName='AnonymousPro', fontWeight='bold', fontStyle='italic', mimeType='application/x-font')]
private static var AnonymousProBI:Class;
[Embed(source='/fonts/Anonymous Pro I.ttf', embedAsCFF='true', fontName='AnonymousPro', fontWeight='normal', fontStyle='italic', mimeType='application/x-font')]
private static var AnonymousProI:Class;
[Embed(source='/fonts/Anonymous Pro.ttf', embedAsCFF='true', fontName='AnonymousPro', fontWeight='normal', fontStyle='normal', mimeType='application/x-font')]
private static var AnonymousPro:Class;
// TextFlow options
textFlow.fontLookup = FontLookup.EMBEDDED_CFF;
textFlow.cffHinting = CFFHinting.HORIZONTAL_STEM;
textFlow.renderingMode = RenderingMode.CFF;
To use a custom component as a statusbar it's quiet easy,
just create your component using MXML or Actionscript, it's the same, and the add this line to your WindowedApplication
statusBarFactory="{new ClassFactory(MyCustomStatusBar)}"
In the Flex SDK 3.5.0.12683 the ComboBox Class has a strange behavior, if you change the dataprovider after you have played with your ComboBox, the list of item in the dropdown is not refreshed.
Possible solutions to the problem are :
1) Switch back to the 3.4 SDK
2) Add the following few lines of code after updating the dataprovider : myComboBox.dropdown.dataProvider = yourArray;
Enjoy : )
myComboBox.dropdown.dataProvider = yourArray
If you are trying to extend a custom component and you get the following error
"Multiple sets of visual children have been specified for this component (base component definition and derived component definition)."
the problem is that you have created an MXML component with some children hardcoded;
Surfing the net I've found an interesting discussion
here but the solution provided there hasn't convinced me at all.
After some attempts I've finally found a nice solution that is not to hardcode components inside the MXML but create components using actionscript and then add them to the displayList in the createChildren method.
override protected function childrenCreated():void{
super.childrenCreated();
if(!btn){
btn = new Button();
btn.label = "my as button";
addChild(btn);
}
}