Tuesday, December 29, 2009

Flex Image Centering

I was trying to get an image that was scaled to be centered on the screen and realized that Flex has some issues doing this. Using horizontalCenter="0" verticalCenter="0" will not work because whether you set the width and height or the maxWidth and maxHeight the image will fill the whole space. So, it an image is taller than it is wide it will still be left aligned.

To fix this I came across guille’s blog and after reading the comment "Anyone got something cleaner" I gave it a shot.

Here is my fix.
I consider using the maxHeight and maxWidth to be the appropriate method and I assume that you would also like to stretch the image out to fill the box. If you set the maxWidth and maxHeight then you can use add the following as the compete listener ( complete="onImageComplete(event)" )
protected function onImageComplete( e:Event ):void
{
 var image:Image = e.target as Image;

 var ratio:Number = Math.min( image.maxWidth/image.contentWidth, image.maxHeight/image.contentHeight );
 image.width = ratio * image.contentWidth;
 image.height = ratio * image.contentHeight;
}


If you don't want the image to stretch out, then just add 1 as another argument into the min function. The ratio will never be greater than one and the image will never be made larger than it was.
protected function onImageComplete( e:Event ):void
{
 var image:Image = e.target as Image;

 var ratio:Number = Math.min( 1, image.maxWidth/image.contentWidth, image.maxHeight/image.contentHeight );
 image.width = ratio * image.contentWidth;
 image.height = ratio * image.contentHeight;
}

Working Example

Flex Image Centering Example

Wednesday, November 18, 2009

Flex Code Behind 2

In my last post I talked about separating layout and code using a code behind method. There are some more tricks you can use, and some standards I follow to keep things consistent. To recap a little I refer to a code behind class as an ActionScript class that is extended by a MXML class.


MainForm

Because every flex application has to have one MXML class that extends Application, and not a class that inherits Application, it can't have a code behind. To get around this I create one MXML class with a code behind, call it MainForm, and put it in the Application. I use that MainForm.mxml to lay out the main components and it can have a MainFormClass.as code behind. The MainForm is the only thing in the Application.mxml and I never touch the Application.mxml again.


Example Application.mxml:

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"

 xmlns="view.*"

 layout="absolute">

 <MainForm height="100%" width="100%" />

</mx:Application>


Data bind everything

If you want to display a response in a label don't set the label's text property, instead create a bindable string in the code behind and bind the label's text to that. If later you want to switch to a Textarea you can just change the MXML and not the definition in the code behind.


Good Example (using binding):

mxml

<mx:Label text="{confirmation}" />

as

[Bindable] protected var confirmation:String;

...

confirmation = "Add to cart qty:"+qty;


Bad Example (not using binding:

mxml

<mx:Label id="confirmation" />

as

public var confirmation:Label;

...

confirmation.text = "Add to cart qty:"+qty;


Avoiding IDs in the code behind

Data binding everything helps, but in the event you want to get information from components you will need to use ids, but that doesn't mean you need them in the code behind class. In my last post I broke this rule to show that you can refer to components by id in a code behind class. In stead of grabbing the text from the component in the submit function, pass the text to the submit function from the MXML.


Good Example (no IDs in as file):

mxml

<mx:TextInput id="qty" enter="addToCart(qty.text)" width="33" />

as

protected function addToCart( qty:String ):void

{

 confirmation = "Add to cart qty:"+qty;

}


Bad Example (IDs in mxml and as file):

mxml

<mx:TextInput id="qty" enter="addToCart()" width="33" />

as

public var qty:TextInput;

...

protected function addToCart():void

{

 confirmation = "Add to cart qty:"+qty.text;

}

Monday, November 2, 2009

Flex Code Behind

ASP pages usually are made of a frontend and a backend. I am by no means a Microsoft fan, but I do like the separation of markup and logic. Coming from a flash background having a separate ActionScript file with all my code just feels right.

With Flex there is no need for AS files. All the code could be in the MXML and use script tags, but I think script tags complicate the view. Instead of using script tags. Make an ActionScript class that extends the UIComponent you want to inherit and make an MXML class that inherits from your ActionScript class. I like to name the MXML class something descriptive and use the same name plus Class for the ActionScript class.

Example:
ProductView.mxml
ProductViewClass.as

To share functions: Define a protected or public function in the AS class and call them in the MXML.
To display information in the MXML make protected variables and data bind to them, preferably a model object. I will omit a MVC discussion for later.
To alter MXML elements, I prefer to data bind to variables, but if you need a handel to a UIComponent give it an ID in the MXML and create a public variable in the AS class. Try to avoid this. It makes your ActionScript class depend on the MXML. Instead most updates can be done by data binding to variables that change in the AS class.

Here is a simple example of a ProductView with a code behind class. The MXML data binds to a product, and the code behind reads the qty.text. I will include more examples in future posts.

ProductView.mxml

<?xml version="1.0" encoding="utf-8"?>

<ProductViewClass

 xmlns:mx="http://www.adobe.com/2006/mxml"

 xmlns="view.*"

 >

 <mx:HBox >

  <mx:VBox>

   <mx:Label text="{product.description}" />

   <mx:Label text="Price ${product.price}" />

  </mx:VBox>

  <mx:Label text="Qty: " />

  <mx:TextInput id="qty" enter="addToCart()" width="33" />

  <mx:Button label="Add To Cart" click="addToCart()" />

 </mx:HBox>

</ProductViewClass>


ProductViewClass.as

package view

{

 import model.Product;

 import mx.containers.Canvas;

 import mx.controls.Alert;

 import mx.controls.TextInput;


 public class ProductViewClass extends Canvas

 {

  [Bindable]

  protected var product:Product;

  public var qty:TextInput;

  public function ProductViewClass()

  {

   product = new Product();

  }

  protected function addToCart():void

  {

  Alert.show( "Add to cart qty:"+qty.text ); 

  }

 }

}

Tuesday, October 20, 2009

Welcome to my blog

I hope to share what I have learned over the years working in ActionScript. I will try to stick to Flash and Flex but some occasional html, JavaScript, or server side code may slip through.

I enjoy most all programing languages but flash has always been my favorite. I have worked with flash since Flash 5 and have loved it ever since.  Drawing and animating first caught my attention, but pulling elements together with code sold me on it. It reminded me of working in Hyper Card on my old Apple Classic.

Transitioning from hobby to ocupation I worked on a financial modeling application that used only Flash as the user interface. From there I have used flash to build digital photo books, play videos, record videos, colaborate simultaniously, visulaize data, and simulate environments.

I have facilitated several workshops and enjoy seeing the Flash community grow. To continue with that effort over time I will showcase some old projects, show off some new ones, and preach about best practices.

Enjoy and stay tuned.