while(thoughts){ "i am writing"}

Just about anything… and everything :)

Archive for December 2010

Flex 4 : Vector Graphics in Spark

with one comment

In Spark, we have support for vector graphics that can be used in our applications. In contrast with Bitmap graphics where you show one bit at a time, Vector graphics are calculated mathematically. Hence, as you shrink or grow your view, the graphics will give you a smooth experience.
Vector graphics are kept in the spark.primitives package.
Note: Vector graphics can only be added to spark containers. It does not support old mx containers from Flex 3.

There are 3 primary classes that you can use to create your graphics. These are:
Rect
Ellipse
Path

We will discuss about them in the coming posts.

Written by MD

December 24, 2010 at 1:47 PM

Flex 4: Layouts supported in Spark

leave a comment »

By default, Spark supports four layouts as given below:
spark.layouts.BasicLayout
spark.layouts.HorizontalLayout
spark.layouts.TileLayout
spark.layouts.VerticalLayout

Some detail about each of them:
BasicLayout: Its similar to absolute layout that we used to have in previous version of flex. Programmer need to explicitly set the position for each component(essentially the x and y OR constraints). This layout should not be used for List based controls.

HorizontalLayout: arranges the layout elements in horizontal order.

VerticalLayout: arranges the layout elements in vertical order.

TileLayout: arranges the layout elements in rows and columns of equally sized cells. The default size(when not explicitly set), is as square as possible area and is large enough to fit all elements.

Flex 4: Text Controls in Spark

leave a comment »

Spark supports five types of text controls. These are:
Label
RichText
RichEditableText
TextInput
TextArea

A brief about each:
Label – Label is the most light weight text control in spark. It supports a plain text string displayed without any colorful background.

RichText: Similar to Label, it is the next lightweight text control. It supports backgroundColor property in addition to other properties on Label.

RichEditableText: As the name suggests, it has editable text in addition to RichText control.

TextInput: A single line text input control. In addition, it has ‘displayAsPassword’ property.

TextArea: A multiline text control with scrollbar (when needed). It also supports ‘displayAsPassword’ property.

Written by MD

December 18, 2010 at 7:29 PM

Flex 4: Alternatives to Canvas

leave a comment »

Lately, I was looking to use Canvas in my experiment with Flex 4 and found that Canvas is not included in Spark components. Instead I was recommended to use spark.components.BorderContainer OR
spark.components.Group
class.
So, why not Canvas? A good reason for this would be that Canvas was essentially a rectangular container that allowed a programmer to define the x and y properties for its children. So it was kind of a plain container.
In spark, we have BorderContainer which typically does not need a skin. Instead you can use CSS styles with it.
Also, a Group container can be used in place of Canvas. As it just meant to hold the children, to keep it lightweight and for the performance reasons, it can not be skinned.

Written by MD

December 10, 2010 at 10:10 AM

Flex 4: Spark Component Life Cycle

with one comment

In our previous post, we learned about Skins used in Spark Components. Skins are an integral part of Spark Components OR we can say that skins are actually the building blocks for skinnable spark components.

Today, we will discuss about the life cycle of a skinnable spark component. During this discussion, we will create an actual component as part of this learning. I am not going through the screenshots, instead I will be sharing the code snippets for various steps. You can find the complete source code at the end of this post.

Lets call out skinnable component as ‘CustomComponent’. It will have a textinput to write a message, an append button and a text area with disabled text. User will be able to type the text in textinput control and on click of the append button, this text will be appended to the existing text in textarea.

First we need to create a skin for our CustomComponent. Lets call it CustomComponentSkin.

Steps to create a skin:

  • In Flashbuilder, right click on your mouse. Select New > MXML Skin.
  • In the opened dialog, give ‘skin’ as package name. Name will be ‘CustomComponentSkin’ and Host Component will be ‘CustomComponent’.
  • Click Ok and Flashbuilder will create a Skin with default settings.

In Spark, a component is made up of a skin and a component class. Skin class actually hold the parts(in our case, textinput, button and textarea) and component class manipulates these parts and their properties for various functionalities.

So we need to create those parts(textinput, button and textarea) in CustomComponentSkin as below:


<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
 xmlns:s="library://ns.adobe.com/flex/spark"
 xmlns:mx="library://ns.adobe.com/flex/mx">

 <!-- host component -->
 <fx:Metadata>
 [HostComponent("ui.CustomComponent")]
 </fx:Metadata>

 <!-- Define the normal view state. -->
 <s:states>
 <s:State name="normal"/>
 </s:states>

 <!--- Defines the appearance of the TextInput subcomponent. -->
 <s:TextInput id="textInput"
 width="150"
 x="0"
 minHeight="25"/>

 <!--- Defines the appearance of the Button subcomponent. -->
 <s:Button id="appendButton"
 width="150"
 x="175"
 minHeight="25"/>

 <!--- Defines the appearance of the TextArea subcomponent. -->
 <s:TextArea id="textArea"
 width="400"
 x="0"
 y="50"/>
</s:Skin>

As you have noticed, we also provided the metadata tag HostComponent pointing to our CustomComponent.

Now we have our components skin ready, lets move to create the actual component. Before we create our component, I would prefer to step through the various calls/functions used for it quickly (from adobe docs).

  1. Create the skin class for the component. You typically create the skin class in MXML. For more information on skins, see Spark Skinning.
  2. Create the component’s ActionScript class file.
    1. For a skinnable component, extend one of the base classes, such as SkinnableComponent, or a subclass of class SkinnableComponent. For a nonskinnable component, extend UIComponent or a Spark class that does not have SkinnableComponent in it class hierarchy.
    2. Implement the constructor.
    3. Implement the UIComponent.createChildren() method. You rarely have to implement this method for Spark components.
    4. Implement the UIComponent.commitProperties() method.
    5. Implement the UIComponent.measure() method. You rarely have to implement this method for Spark components.
    6. Implement the UIComponent.updateDisplayList() method. You rarely have to implement this method for Spark components.
    7. For a skinnable component, implement the SkinnableComponent.partAdded() and SkinnableComponent.partRemoved() methods.
    8. For a skinnable component, implement the SkinnableComponent.getCurrentSkinState() method.
    9. Add properties, methods, styles, events, and metadata.
  3. Deploy the component as an ActionScript file or as a SWC file.

You do not have to override all component methods to define a new component. You only override the methods required to implement the functionality of your component. If you create a subclass of an existing component, such as Button, you implement only the methods necessary for you to add any new functionality to the component.

Lets step through the component creation with the implementation of necessary functions:

  • In Flashbuilder, right click and select New > ActionScript Class.
  • Type in ‘ui’ as the package name, ‘CustomComponent’ in the name field and select ‘SkinnableComponent’ as the super class.
  • Click Finish. Flashbuilder will generate the wrapper class structure with a default constructor.
  • Set the skinclass (that we just created above) in the constructor using setStyle function as shown below:


package ui
{
 import spark.components.supportClasses.SkinnableComponent;

 public class CustomComponent extends SkinnableComponent
 {
 public function CustomComponent()
 {
 super();

 // Set the skinClass style to the name of the skin class.
 setStyle("skinClass", CustomComponentSkin);
 }
 }
}

  • In next step, define the skin parts for the TextInput, Button and TextArea subcomponents and implement the commitProperties() method to handle any changes to the CustomComponent’s properties as shown below:


[SkinPart(required="true")]
 public var textInput:TextInput;

 [SkinPart(required="true")]
 public var appendButton:Button;

 [SkinPart(required="true")]
 public var textArea:TextArea;

override protected function commitProperties():void {
 super.commitProperties();

 if (bTextChanged) {
 bTextChanged = false;
 textInput.text = _text;
 }
 }

  • In next step, implement the partAdded() method to initialize  the TextInput, Button and TextArea subcomponents. Also implement the partRemoved() method to remove the eventlisteners added by the partAdded().


override protected function partAdded(partName:String, instance:Object):void {
 super.partAdded(partName, instance);
 if (instance == textInput) {
 textInput.text= _text;
 textInput.addEventListener("change", textInput_changeHandler);
 }

 if (instance == appendButton) {
 appendButton.label = "Append Text";
 appendButton.addEventListener("click", appendButton_clickHandler);
 }

 if (instance == textArea) {
 textArea.editable = false;
 }
 }

override protected function partRemoved(partName:String, instance:Object):void {
 super.partRemoved(partName, instance);

 if (instance == textInput) {
 textInput.removeEventListener("change", textInput_changeHandler);
 }

 if (instance == appendButton) {
 appendButton.removeEventListener("click", appendButton_clickHandler);
 }

 if (instance == textArea) {
 //textArea.removeEventListener("change", textArea_changeHandler);
 }
 }

  • In the next step, add properties, methods and metadata.


private var _text:String = "Enter your text";
 private var bTextChanged:Boolean = false;

 // Create a getter/setter pair for the text property.
 [Bindable]
 public function set text(t:String):void {
 trace("In set text");
 _text = t;
 bTextChanged = true;
 invalidateProperties();
 }

 public function get text():String {
 trace("In get text");
 return textInput.text;
 }

 // Dispatch a change event when the CustomComponent.text
 // property changes.
 private function textInput_changeHandler(eventObj:Event):void {
 dispatchEvent(new Event("change"));
 }

 // Handle the Button click event to append text
 // to the TextArea subcomponent.
 private function appendButton_clickHandler(eventObj:Event):void {
 if(textInput.text.length < 5)
 {
 textArea.text += "Oh.. sorry buddy. You were less then 5, the minimum required length..hehehe..\n" + "[Text length this turn: " + textInput.text.length + "]\n\n";
 }
 else
 {
 textArea.text += textInput.text + "\n" + "[Text length this turn: " + textInput.text.length + "]\n\n";
 }
 }

And we are done.

Here is how our CustomComponent.as will look like finally. I have added the steps and trace statements for various function calls to better understand the control flow. It has some additional functions just to trace the control flow in a component life cycle.


package ui
{
 import flash.events.Event;

 import mx.events.FlexEvent;

 import skin.CustomComponentSkin;

 import spark.components.Button;
 import spark.components.TextArea;
 import spark.components.TextInput;
 import spark.components.supportClasses.SkinnableComponent;

 // CustomComponent dispatches a change event when the text of the
 // TextInput subcomponent changes.
 [Event(name="change", type="flash.events.Event")]

 /** a) Extend SkinnableComponent. */
 public class CustomComponent extends SkinnableComponent
 {
 /** b) Implement the constructor. */
 public function CustomComponent()
 {
 //TODO: implement function
 trace("In constructor");
 super();

 // Set the skinClass style to the name of the skin class.
 setStyle("skinClass", CustomComponentSkin);

 //Adding eventlisteners
 addEventListener(FlexEvent.PREINITIALIZE, preInitializeHandler);
 addEventListener(FlexEvent.INITIALIZE, initializeHandler);
 addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
 addEventListener(FlexEvent.UPDATE_COMPLETE, updateCompleteHandler);
 }

 override protected function createChildren():void {
 trace("In createChildren");
 super.createChildren();
 }

 /** c) Define the skin parts for the TextInput, Button
 *     and TextArea subcomponents. **/
 [SkinPart(required="true")]
 public var textInput:TextInput;

 [SkinPart(required="true")]
 public var appendButton:Button;

 [SkinPart(required="true")]
 public var textArea:TextArea;

 /** d) Implement the commitProperties() method to handle the
 *     change to the CustomComponent.text property.
 *     Changes to the CustomComponent.text property are copied to
 *     the TextArea subcomponent. */
 override protected function commitProperties():void {
 trace("In commitProperties");
 super.commitProperties();

 if (bTextChanged) {
 bTextChanged = false;
 textInput.text = _text;
 }
 }

 override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
 trace("In updateDisplayList");
 super.updateDisplayList(unscaledWidth, unscaledHeight);
 }

 override protected function measure():void {
 trace("In measure");
 super.measure();
 }

 override protected function attachSkin():void {
 trace("In attachSkin");
 super.attachSkin();
 }

 override protected function detachSkin():void {
 trace("In detachSkin");
 super.detachSkin();
 }

 /** e) Implement the partAdded() method to
 *     initialize the TextInput, Button and TextArea subcomponents. */
 override protected function partAdded(partName:String, instance:Object):void {
 trace("In partAdded");
 super.partAdded(partName, instance);
 if (instance == textInput) {
 textInput.text= _text;
 textInput.addEventListener("change", textInput_changeHandler);
 }

 if (instance == appendButton) {
 appendButton.label = "Append Text";
 appendButton.addEventListener("click", appendButton_clickHandler);
 }

 if (instance == textArea) {
 textArea.editable = false;
 }
 }

 /** f) Implement the partRemoved() method to remove the
 *     event listeners added by partAdded(). */
 override protected function partRemoved(partName:String, instance:Object):void {
 trace("In partRemoved");
 super.partRemoved(partName, instance);

 if (instance == textInput) {
 textInput.removeEventListener("change", textInput_changeHandler);
 }

 if (instance == appendButton) {
 appendButton.removeEventListener("click", appendButton_clickHandler);
 }

 if (instance == textArea) {
 //textArea.removeEventListener("change", textArea_changeHandler);
 }
 }

 /** g) Add methods, properties, and metadata.
 *     The general pattern for properties is to specify a
 *     private holder variable. */

 // Implement the CustomComponent.text property.
 private var _text:String = "Enter your text";
 private var bTextChanged:Boolean = false;

 // Create a getter/setter pair for the text property.
 [Bindable]
 public function set text(t:String):void {
 trace("In set text");
 _text = t;
 bTextChanged = true;
 invalidateProperties();
 }

 public function get text():String {
 trace("In get text");
 return textInput.text;
 }

 // Dispatch a change event when the CustomComponent.text
 // property changes.
 private function textInput_changeHandler(eventObj:Event):void {
 dispatchEvent(new Event("change"));
 }

 // Handle the Button click event to append text
 // to the TextArea subcomponent.
 private function appendButton_clickHandler(eventObj:Event):void {
 if(textInput.text.length < 5)
 {
 textArea.text += "Oh.. sorry buddy. You were less then 5, the minimum required length..hehehe..\n" + "[Text length this turn: " + textInput.text.length + "]\n\n";
 }
 else
 {
 textArea.text += textInput.text + "\n" + "[Text length this turn: " + textInput.text.length + "]\n\n";
 }
 }

 private function preInitializeHandler(eventObj:Event):void {
 trace("In preInitialize");
 }
 private function initializeHandler(eventObj:Event):void {
 trace("In initialize");
 }
 private function creationCompleteHandler(eventObj:Event):void {
 trace("In creationcomplete");
 }
 private function updateCompleteHandler(eventObj:Event):void {
 trace("In updatecomplete");
 }

 }
}

You can download the complete project source code from here.

Enjoy flexing :)

Written by MD

December 8, 2010 at 9:15 PM

Flex 4: Spark Component Overview

leave a comment »

Spark component = Component + Skin

As you see above a spark component is equivalent to a component (which has all the functionality defined) and a skin (which describes a components visual behavior).

Spark components are generally referred as ‘Skinnable Spark Components’. Spark components can swap a skin at runtime.

Looking at the spark package, one will find that every (skinnable) spark component is associated with a default spark skin through defaults.css (can be found at sdks\4.x.x\frameworks\projects\spark\defaults.css) which has entries like:


NumericStepper
 {
 skinClass: ClassReference("spark.skins.spark.NumericStepperSkin");
 }

Looking into Skins:

Skin Parts:

As I mentioned, a skin defines the visual behavior of a component. It consists multiple constituent elements to make a whole component. For example, a NumericStepper component usually has 3 parts: a textinput, an up (increment) button and a down (decrement) button. Now these 3 parts are defined with a new metadata tag called [SkinPart(required="true")] where ‘required’ can be ‘true’ or ‘false’. As for the NumericStepper, a textinput is a required part and rest 2 buttons are not mandatory.

One important point to note here is that these parts are defined in component class (spark.components.NumericStepper) while their visual appearance and implementation is defined in skin class (spark.skins.spark.NumericStepperSkin).

State Changes:

Often state changes meant to cause the visual appearance to be changed and hence skin changes to reflect the state changes. So, the states are declared in skin classes and used to identify different states that a component can assume visually.

We will discuss the Spark Component Life Cycle in the next post.

Written by MD

December 3, 2010 at 12:12 PM

Flex 4: NumericStepper vs Spinner

leave a comment »

NumericStepper is similar to Spinner (infact extends Spinner) except that it allows user to directly edit the value of the component.

Written by MD

December 1, 2010 at 10:20 AM

Follow

Get every new post delivered to your Inbox.