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);
}
}
a new class was added in Nabiro: MarchingAntsRect wich render a rectangle with dotted line, used to represent a selection area, here is a very simple demo:
<?xml version="1.0"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
width="800" height="600"
layout="absolute">
<mx:Script>
<![CDATA[
import com.gnstudio.nabiro.ui.MarchingAntsRect;
override protected function childrenCreated():void{
super.childrenCreated();
var maRect1:MarchingAntsRect = new MarchingAntsRect();
var r1:Rectangle = new Rectangle(10, 30, 100, 30);
maRect1.draw(r1);
var maRect2:MarchingAntsRect = new MarchingAntsRect();
var r2:Rectangle = new Rectangle(130, 80, 200, 400);
maRect2.draw(r2);
var maRect3:MarchingAntsRect = new MarchingAntsRect();
var r3:Rectangle = new Rectangle(10, 170, 30, 160);
maRect1.draw(r3);
mainPanel.addChild(maRect1);
mainPanel.addChild(maRect2);
mainPanel.addChild(maRect3);
}
]]>
</mx:Script>
<mx:Panel id="mainPanel" width="100%" height="100%" />
</mx:Application>
Anytime you want to get the effect that an object is snapped to a point or to a guide put in place a small helper class like to following where the snapSize is the distance in pixel to use in the snapTo calculation.
package
{
import flash.geom.Point;
public class Snapper{
private var currentPosition:Point;
public function Snapper(position:Point){
currentPosition = position;
}
public function snapTo(snapSize:Number):Point{
var pointTo:Point = new Point();
pointTo.x = currentPosition.x - currentPosition.x % snapSize;
pointTo.y = currentPosition.y - currentPosition.y % snapSize;
return pointTo;
}
}
}
If you want to perform a check between two bounding boxes you can use the following class that is able to detect if the boxes collide or are aligned on one of the corners.
package
{
import flash.geom.Rectangle;
public class BoundingBox
{
public static const TOP_LEFT_ALIGNED:int = 0;
public static const TOP_RIGHT_ALIGNED:int = 1;
public static const BOTTOM_LEFT_ALIGNED:int = 2;
public static const BOTTOM_RIGHT_ALIGNED:int = 3;
private var mainBox:Rectangle;
private var secondaryBox:Rectangle;
private var aligned:int;
public static const TOLERANCE:Number = 1;
public function BoundingBox(main:Rectangle, secondary:Rectangle){
mainBox = main;
secondaryBox = secondary;
}
public function get alignedTo():Rectangle{
var alignedTo:Rectangle;
switch(true){
case mainBox.x > secondaryBox.x - TOLERANCE && mainBox.x < secondaryBox.x + TOLERANCE:
aligned = TOP_LEFT_ALIGNED;
alignedTo = secondaryBox;
break;
case mainBox.y > secondaryBox.y - TOLERANCE && mainBox.y < secondaryBox.y + TOLERANCE:
aligned = BOTTOM_LEFT_ALIGNED;
alignedTo = secondaryBox;
break;
case mainBox.x + mainBox.width > (secondaryBox.x + secondaryBox.width) - TOLERANCE && mainBox.x + mainBox.width < (secondaryBox.x + secondaryBox.width) + TOLERANCE:
aligned = TOP_RIGHT_ALIGNED;
alignedTo = secondaryBox;
break;
case mainBox.y + mainBox.height > (secondaryBox.y + secondaryBox.height) - TOLERANCE && mainBox.y + mainBox.height < (secondaryBox.y + secondaryBox.height) + TOLERANCE:
aligned = BOTTOM_RIGHT_ALIGNED;
alignedTo = secondaryBox;
break;
}
return alignedTo;
}
public function get collideTo():Boolean{
if(mainBox.x > (secondaryBox.x + secondaryBox.width)){
return false; // mainBox is too far right, no collision
} else if((mainBox.x + mainBox.width) < secondaryBox.x){
return false; // mainBox is too far left, no collision
} else if(mainBox.y > (secondaryBox.y + secondaryBox.height)){
return false; // mainBox is too far down, no collision
} else if((mainBox.y + mainBox.height) < secondaryBox.y){
return false; // mainBox is too far up, no collision
} else{
return true; // there is a collision
}
}
public function get direction():int{
return aligned;
}
}
}
If you define a custom style property for your components, you may need a default value for that style, in order to be able to read it (from inside or outside the component) without setting it before (or getting an exception).
During the class initialization the stylemanager checks if there's a style declared for the component. If not it creates a new style declaration. The defaultFactory take care of setting the default values. If a property isn't set in your custom style (css file or other ways) the default value will be used.
Kudos to Ivan for the code tweaking.
package
{
import mx.core.UIComponent;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;
/**
* Custom styles for custom component.
*/
[Style(name="thickness", type="uint", format="Number", inherit="no")]
[Style(name="backgroundColor", type="uint", format="Colors", inherit="no")]
public class MyCustomComponent extends UIComponent
{
private static var classConstructed:Boolean = classConstruct();
private static function classConstruct():Boolean
{
var defStyles:CSSStyleDeclaration = StyleManager.getStyleDeclaration("MyCustomComponent");
if (!defStyles)
{
defStyles = new CSSStyleDeclaration();
StyleManager.setStyleDeclaration("MyCustomComponent ", defStyles, true);
}
defStyles.defaultFactory = function():void
{
this.backgroundColor = 0xCCCCCC;
this.thickness = 20;
}
return true;
}
public function MyCustomComponent()
{
super();
}
}
}
When you use Resource Bundles in you application you can access them through the ResourceManager class, in an MXML file you can get the same resoult through the @Resource directive, obviously you to pass the key and the name fo the file.
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Form>
<mx:FormItem label="@Resource(key='name', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='address', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
<mx:FormItem label="@Resource(key='city', bundle='RegistrationForm')">
<mx:TextInput/>
</mx:FormItem>
</mx:Form>
</mx:Application>
Even if you don't apply scale to the Shape and draw a very long line (e.g. 76800 pixels long), Flash Player has problems maintaining the stroke thickness. You can use this snippet to draw a black rectangle 1 pixel tick and maintain the exact thickness even if you draw a extremely long line. Same technique can be observed in the Flex HRule and VRule classes. Note that the line gets blurred if you don't draw the rectangles using round numbers.
private var border:Shape = new Shape();
private function renderBorder():void {
if (!border.parent)
addChild(border);
var strokeThickness:int = 1;
var strokeColor:uint = 0x000000;
var borderRect:Rectangle = new Rectangle(0, 0, 76800, 51200);
border.x = 40;
border.y = 40;
var g:Graphics = border.graphics;
g.clear();
// Uncomment following lines to see the issue when using standard way to draw lines.
// g.lineStyle(strokeThickness, strokeColor);
// g.drawRect(borderRect.x, borderRect.y, borderRect.width, borderRect.height);
g.beginFill(strokeColor);
g.drawRect(borderRect.x, borderRect.y, borderRect.width, borderRect.height);
g.drawRect(borderRect.x + strokeThickness, borderRect.y + strokeThickness, borderRect.width - (2 * strokeThickness), borderRect.height - (2 * strokeThickness));
g.endFill();
}